From ead1e3c793e317d5be1509805cf5be4a1fe2260a Mon Sep 17 00:00:00 2001 From: Colin Basnett Date: Wed, 28 Feb 2024 00:51:33 -0800 Subject: [PATCH] Initial commit of UT99 poly flags --- io_scene_psk_psa/__init__.py | 8 +++++ io_scene_psk_psa/psk/builder.py | 17 +++++----- io_scene_psk_psa/psk/export/operators.py | 14 ++++----- io_scene_psk_psa/psk/export/properties.py | 6 ++-- io_scene_psk_psa/psk/export/ui.py | 2 +- io_scene_psk_psa/psk/properties.py | 38 +++++++++++++++++++++++ io_scene_psk_psa/psk/ui.py | 28 +++++++++++++++++ io_scene_psk_psa/types.py | 2 +- 8 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 io_scene_psk_psa/psk/properties.py create mode 100644 io_scene_psk_psa/psk/ui.py diff --git a/io_scene_psk_psa/__init__.py b/io_scene_psk_psa/__init__.py index 7570fe9..4076dd9 100644 --- a/io_scene_psk_psa/__init__.py +++ b/io_scene_psk_psa/__init__.py @@ -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) @@ -50,6 +52,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 @@ -72,6 +76,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 +\ @@ -107,6 +113,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) @@ -114,6 +121,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 diff --git a/io_scene_psk_psa/psk/builder.py b/io_scene_psk_psa/psk/builder.py index 081be45..2ba6c34 100644 --- a/io_scene_psk_psa/psk/builder.py +++ b/io_scene_psk_psa/psk/builder.py @@ -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 get_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 @@ -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 = get_poly_flags(material.psk) + print(psk_material.name, psk_material.poly_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 diff --git a/io_scene_psk_psa/psk/export/operators.py b/io_scene_psk_psa/psk/export/operators.py index a902b27..98d8f4f 100644 --- a/io_scene_psk_psa/psk/export/operators.py +++ b/io_scene_psk_psa/psk/export/operators.py @@ -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: diff --git a/io_scene_psk_psa/psk/export/properties.py b/io_scene_psk_psa/psk/export/properties.py index 8382d01..bdb6493 100644 --- a/io_scene_psk_psa/psk/export/properties.py +++ b/io_scene_psk_psa/psk/export/properties.py @@ -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() diff --git a/io_scene_psk_psa/psk/export/ui.py b/io_scene_psk_psa/psk/export/ui.py index 6a7a056..4fa55af 100644 --- a/io_scene_psk_psa/psk/export/ui.py +++ b/io_scene_psk_psa/psk/export/ui.py @@ -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 = ( diff --git a/io_scene_psk_psa/psk/properties.py b/io_scene_psk_psa/psk/properties.py new file mode 100644 index 0000000..2719336 --- /dev/null +++ b/io_scene_psk_psa/psk/properties.py @@ -0,0 +1,38 @@ +from bpy.props import EnumProperty +from bpy.types import PropertyGroup + +mesh_triangle_types_items = ( + ('MTT_Normal', 'Normal', 'Normal one-sided', 0), + ('MTT_NormalTwoSided', 'Normal Two-Sided', 'Normal but two-sided', 1), + ('MTT_Translucent', 'Translucent', 'Translucent two-sided', 2), + ('MTT_Masked', 'Masked', 'Masked two-sided', 3), + ('MTT_Modulate', 'Modulate', 'Modulation blended two-sided', 4), + ('MTT_Placeholder', 'Placeholder', 'Placeholder triangle for positioning weapon. Invisible', 8), +) + +mesh_triangle_bit_flags_items = ( + ('MTT_Unlit', 'Unlit', 'Full brightness, no lighting', 16), + ('MTT_Flat', 'Flat', 'Flat surface, don\'t do bMeshCurvy thing', 32), + ('MTT_Environment', 'Environment', 'Environment mapped', 64), + ('MTT_NoSmooth', '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 get_poly_flags(material: PSX_PG_material) -> int: + poly_flags = 0 + poly_flags |= mesh_triangle_types_items_dict[material.mesh_triangle_type] + for flag in material.mesh_triangle_bit_flags: + poly_flags |= mesh_triangle_bit_flags_items_dict[flag] + return poly_flags + +classes = ( + PSX_PG_material, +) diff --git a/io_scene_psk_psa/psk/ui.py b/io_scene_psk_psa/psk/ui.py new file mode 100644 index 0000000..a3577b0 --- /dev/null +++ b/io_scene_psk_psa/psk/ui.py @@ -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, +) diff --git a/io_scene_psk_psa/types.py b/io_scene_psk_psa/types.py index ae3e9a9..4f13902 100644 --- a/io_scene_psk_psa/types.py +++ b/io_scene_psk_psa/types.py @@ -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, )