1
0
mirror of https://github.com/DarklightGames/io_scene_psk_psa.git synced 2024-11-13 18:00:52 +01:00

Merge branch 'master' into blender-4.1

This commit is contained in:
Colin Basnett 2024-03-11 18:46:24 -07:00
commit b67c734687
10 changed files with 115 additions and 24 deletions

View File

@ -3,7 +3,7 @@ from bpy.app.handlers import persistent
bl_info = {
'name': 'PSK/PSA Importer/Exporter',
'author': 'Colin Basnett, Yurii Ti',
'version': (6, 1, 2),
'version': (6, 2, 0),
'blender': (4, 0, 0),
'description': 'PSK/PSA Import/Export (.psk/.psa)',
'warning': '',
@ -24,6 +24,8 @@ if 'bpy' in locals():
importlib.reload(psk_writer)
importlib.reload(psk_builder)
importlib.reload(psk_importer)
importlib.reload(psk_properties)
importlib.reload(psk_ui)
importlib.reload(psk_export_properties)
importlib.reload(psk_export_operators)
importlib.reload(psk_export_ui)
@ -51,6 +53,8 @@ else:
from .psk import writer as psk_writer
from .psk import builder as psk_builder
from .psk import importer as psk_importer
from .psk import properties as psk_properties
from .psk import ui as psk_ui
from .psk.export import properties as psk_export_properties
from .psk.export import operators as psk_export_operators
from .psk.export import ui as psk_export_ui
@ -73,6 +77,8 @@ import bpy
from bpy.props import PointerProperty
classes = psx_types.classes +\
psk_properties.classes +\
psk_ui.classes +\
psk_import_operators.classes +\
psk_export_properties.classes +\
psk_export_operators.classes +\
@ -108,6 +114,7 @@ def register():
bpy.types.TOPBAR_MT_file_import.append(psk_import_menu_func)
bpy.types.TOPBAR_MT_file_export.append(psa_export_menu_func)
bpy.types.TOPBAR_MT_file_import.append(psa_import_menu_func)
bpy.types.Material.psk = PointerProperty(type=psk_properties.PSX_PG_material)
bpy.types.Scene.psa_import = PointerProperty(type=psa_import_properties.PSA_PG_import)
bpy.types.Scene.psa_export = PointerProperty(type=psa_export_properties.PSA_PG_export)
bpy.types.Scene.psk_export = PointerProperty(type=psk_export_properties.PSK_PG_export)
@ -115,6 +122,7 @@ def register():
def unregister():
del bpy.types.Material.psk
del bpy.types.Scene.psa_import
del bpy.types.Scene.psa_export
del bpy.types.Scene.psk_export

View File

@ -111,7 +111,7 @@ def get_animation_data_object(context: Context) -> Object:
if active_object.type != 'ARMATURE':
raise RuntimeError('Selected object must be an Armature')
if pg.should_override_animation_data:
if pg.sequence_source != 'ACTIONS' and pg.should_override_animation_data:
animation_data_object = pg.animation_data_override
else:
animation_data_object = active_object

View File

@ -3,9 +3,10 @@ from typing import Optional
import bmesh
import bpy
import numpy as np
from bpy.types import Armature
from bpy.types import Armature, Material
from .data import *
from .properties import triangle_type_and_bit_flags_to_poly_flags
from ..helpers import *
@ -20,7 +21,7 @@ class PskBuildOptions(object):
self.bone_filter_mode = 'ALL'
self.bone_collection_indices: List[int] = []
self.use_raw_mesh_data = True
self.material_names: List[str] = []
self.materials: List[Material] = []
self.should_enforce_bone_name_restrictions = False
@ -75,9 +76,9 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
psk = Psk()
bones = []
if armature_object is None:
# If the mesh has no armature object, simply assign it a dummy bone at the root to satisfy the requirement
# that a PSK file must have at least one bone.
if armature_object is None or len(armature_object.data.bones) == 0:
# If the mesh has no armature object or no bones, simply assign it a dummy bone at the root to satisfy the
# requirement that a PSK file must have at least one bone.
psk_bone = Psk.Bone()
psk_bone.name = bytes('root', encoding='windows-1252')
psk_bone.flags = 0
@ -138,19 +139,21 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
psk.bones.append(psk_bone)
# MATERIALS
material_names = options.material_names
for material_name in material_names:
for material in options.materials:
psk_material = Psk.Material()
try:
psk_material.name = bytes(material_name, encoding='windows-1252')
psk_material.name = bytes(material.name, encoding='windows-1252')
except UnicodeEncodeError:
raise RuntimeError(f'Material name "{material_name}" contains characters that cannot be encoded in the Windows-1252 codepage')
raise RuntimeError(f'Material name "{material.name}" contains characters that cannot be encoded in the Windows-1252 codepage')
psk_material.texture_index = len(psk.materials)
psk_material.poly_flags = triangle_type_and_bit_flags_to_poly_flags(material.psk.mesh_triangle_type,
material.psk.mesh_triangle_bit_flags)
psk.materials.append(psk_material)
context.window_manager.progress_begin(0, len(input_objects.mesh_objects))
material_names = [m.name for m in options.materials]
for object_index, input_mesh_object in enumerate(input_objects.mesh_objects):
should_flip_normals = False

View File

@ -20,19 +20,19 @@ def is_bone_filter_mode_item_available(context, identifier):
def populate_material_list(mesh_objects, material_list):
material_list.clear()
material_names = []
materials = []
for mesh_object in mesh_objects:
for i, material_slot in enumerate(mesh_object.material_slots):
material = material_slot.material
# TODO: put this in the poll arg?
if material is None:
raise RuntimeError('Material slot cannot be empty (index ' + str(i) + ')')
if material.name not in material_names:
material_names.append(material.name)
if material not in materials:
materials.append(material)
for index, material_name in enumerate(material_names):
for index, material in enumerate(materials):
m = material_list.add()
m.material_name = material_name
m.material = material
m.index = index
@ -159,9 +159,9 @@ class PSK_OT_export(Operator, ExportHelper):
options.bone_filter_mode = pg.bone_filter_mode
options.bone_collection_indices = [x.index for x in pg.bone_collection_list if x.is_selected]
options.use_raw_mesh_data = pg.use_raw_mesh_data
options.material_names = [m.material_name for m in pg.material_list]
options.materials = [m.material for m in pg.material_list]
options.should_enforce_bone_name_restrictions = pg.should_enforce_bone_name_restrictions
try:
result = build_psk(context, options)
for warning in result.warnings:

View File

@ -1,11 +1,11 @@
from bpy.props import EnumProperty, CollectionProperty, IntProperty, BoolProperty, StringProperty
from bpy.types import PropertyGroup
from bpy.props import EnumProperty, CollectionProperty, IntProperty, BoolProperty, PointerProperty
from bpy.types import PropertyGroup, Material
from ...types import PSX_PG_bone_collection_list_item
class PSK_PG_material_list_item(PropertyGroup):
material_name: StringProperty()
material: PointerProperty(type=Material)
index: IntProperty()

View File

@ -4,7 +4,7 @@ from bpy.types import UIList
class PSK_UL_materials(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
row = layout.row()
row.label(text=str(getattr(item, 'material_name')), icon='MATERIAL')
row.prop(item.material, 'name', text='', emboss=False, icon_value=layout.icon(item.material))
classes = (

View File

@ -7,6 +7,7 @@ from bpy.types import VertexGroup
from mathutils import Quaternion, Vector, Matrix
from .data import Psk
from .properties import poly_flags_to_triangle_type_and_bit_flags
from ..helpers import rgb_to_srgb, is_bdk_addon_loaded
@ -134,6 +135,9 @@ def import_psk(psk: Psk, context, options: PskImportOptions) -> PskImportResult:
else:
# Just create a blank material.
material = bpy.data.materials.new(material_name)
mesh_triangle_type, mesh_triangle_bit_flags = poly_flags_to_triangle_type_and_bit_flags(psk_material.poly_flags)
material.psk.mesh_triangle_type = mesh_triangle_type
material.psk.mesh_triangle_bit_flags = mesh_triangle_bit_flags
material.use_nodes = True
mesh_data.materials.append(material)

View File

@ -0,0 +1,48 @@
from bpy.props import EnumProperty
from bpy.types import PropertyGroup
mesh_triangle_types_items = (
('NORMAL', 'Normal', 'Normal one-sided', 0),
('NORMAL_TWO_SIDED', 'Normal Two-Sided', 'Normal but two-sided', 1),
('TRANSLUCENT', 'Translucent', 'Translucent two-sided', 2),
('MASKED', 'Masked', 'Masked two-sided', 3),
('MODULATE', 'Modulate', 'Modulation blended two-sided', 4),
('PLACEHOLDER', 'Placeholder', 'Placeholder triangle for positioning weapon. Invisible', 8),
)
mesh_triangle_bit_flags_items = (
('UNLIT', 'Unlit', 'Full brightness, no lighting', 16),
('FLAT', 'Flat', 'Flat surface, don\'t do bMeshCurvy thing', 32),
('ENVIRONMENT', 'Environment', 'Environment mapped', 64),
('NO_SMOOTH', 'No Smooth', 'No bilinear filtering on this poly\'s texture', 128),
)
class PSX_PG_material(PropertyGroup):
mesh_triangle_type: EnumProperty(items=mesh_triangle_types_items, name='Triangle Type')
mesh_triangle_bit_flags: EnumProperty(items=mesh_triangle_bit_flags_items, name='Triangle Bit Flags',
options={'ENUM_FLAG'})
mesh_triangle_types_items_dict = {item[0]: item[3] for item in mesh_triangle_types_items}
mesh_triangle_bit_flags_items_dict = {item[0]: item[3] for item in mesh_triangle_bit_flags_items}
def triangle_type_and_bit_flags_to_poly_flags(mesh_triangle_type: str, mesh_triangle_bit_flags: set[str]) -> int:
poly_flags = 0
poly_flags |= mesh_triangle_types_items_dict.get(mesh_triangle_type, 0)
for flag in mesh_triangle_bit_flags:
poly_flags |= mesh_triangle_bit_flags_items_dict.get(flag, 0)
return poly_flags
def poly_flags_to_triangle_type_and_bit_flags(poly_flags: int) -> (str, set[str]):
try:
triangle_type = next(item[0] for item in mesh_triangle_types_items if item[3] == (poly_flags & 15))
except StopIteration:
triangle_type = 'NORMAL'
triangle_bit_flags = {item[0] for item in mesh_triangle_bit_flags_items if item[3] & poly_flags}
return triangle_type, triangle_bit_flags
classes = (
PSX_PG_material,
)

View File

@ -0,0 +1,28 @@
from bpy.types import Panel
class PSK_PT_material(Panel):
bl_label = 'PSK Material'
bl_idname = 'PSK_PT_material'
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = 'material'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.material is not None
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
material = context.material
layout.prop(material.psk, 'mesh_triangle_type')
col = layout.column()
col.prop(material.psk, 'mesh_triangle_bit_flags', expand=True, text='Flags')
classes = (
PSK_PT_material,
)

View File

@ -51,5 +51,5 @@ classes = (
PSX_PG_action_export,
PSX_PG_bone_collection_list_item,
PSX_UL_bone_collection_list,
PSX_PT_action
PSX_PT_action,
)