From 60738197b28fa8e2ec1fba8982c6edc02289d740 Mon Sep 17 00:00:00 2001 From: Jameriquiah Date: Mon, 25 May 2026 06:29:44 -0400 Subject: [PATCH] feature set implementation --- fast64_internal/f3d/f3d_material.py | 71 +++++++++------ fast64_internal/f3d/f3d_texture_writer.py | 20 +++-- fast64_internal/f3d/f3d_writer.py | 24 +++++- fast64_internal/hm64/__init__.py | 4 + fast64_internal/hm64/mm/mm_f3d_writer.py | 25 ++++-- fast64_internal/hm64/mm/skeleton/operators.py | 6 +- fast64_internal/hm64/z64/operators.py | 2 +- fast64_internal/hm64/z64/panels.py | 24 ++++-- fast64_internal/hm64/z64/skeleton_xml.py | 9 +- fast64_internal/utility.py | 7 ++ fast64_internal/z64/__init__.py | 1 + fast64_internal/z64/animated_mats/panels.py | 6 +- fast64_internal/z64/animation/panels.py | 5 ++ fast64_internal/z64/collision/panels.py | 5 ++ fast64_internal/z64/cutscene/motion/panels.py | 5 ++ fast64_internal/z64/cutscene/panels.py | 9 ++ .../z64/exporter/skeleton/__init__.py | 3 +- .../z64/exporter/skeleton/functions.py | 66 ++++---------- fast64_internal/z64/f3d/operators.py | 86 ++++++++++++------- fast64_internal/z64/f3d/properties.py | 83 ++++++++++-------- fast64_internal/z64/file_settings.py | 5 ++ fast64_internal/z64/hackeroot/panels.py | 5 ++ fast64_internal/z64/scene/panels.py | 6 +- fast64_internal/z64/skeleton/constants.py | 8 ++ fast64_internal/z64/skeleton/operators.py | 20 +++-- fast64_internal/z64/skeleton/panels.py | 10 ++- fast64_internal/z64/skeleton/properties.py | 64 +++++++++++--- fast64_internal/z64/tools/panel.py | 5 ++ fast64_internal/z64/utility.py | 4 + 29 files changed, 391 insertions(+), 197 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index d01f4f9b7..a9fee5a47 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -851,6 +851,9 @@ def ui_scale(self, material, layout): return inputGroup def ui_dynamic_cosmetic_entry(self, f3dMat, layout, enabledProp, nameProp, categoryProp): + if not is_hm64_feature_set(): + return + layout.prop(f3dMat, enabledProp, text="Dynamic Cosmetic Entry") if getattr(f3dMat, enabledProp): dynamicEntry = layout.column() @@ -3262,10 +3265,11 @@ def to_dict(self): } if self.use_tex_reference: data["reference"] = self.reference_to_dict() - if self.custom_palette_name: - data["customTLUTName"] = self.custom_palette_name - data["paletteColorCount"] = self.palette_color_count - data["isVanillaTexture"] = self.is_vanilla_texture + if is_hm64_feature_set(): + if self.custom_palette_name: + data["customTLUTName"] = self.custom_palette_name + data["paletteColorCount"] = self.palette_color_count + data["isVanillaTexture"] = self.is_vanilla_texture if self.texture_internal_path: data["internalPath"] = self.texture_internal_path return data @@ -3285,9 +3289,10 @@ def from_dict(self, data: dict): self.use_tex_reference = "reference" in data if self.use_tex_reference: self.reference_from_dict(data["reference"]) - self.custom_palette_name = data.get("customTLUTName", self.custom_palette_name) - self.palette_color_count = data.get("paletteColorCount", self.palette_color_count) - self.is_vanilla_texture = data.get("isVanillaTexture", self.is_vanilla_texture) + if is_hm64_feature_set(): + self.custom_palette_name = data.get("customTLUTName", self.custom_palette_name) + self.palette_color_count = data.get("paletteColorCount", self.palette_color_count) + self.is_vanilla_texture = data.get("isVanillaTexture", self.is_vanilla_texture) self.texture_internal_path = data.get("internalPath", self.texture_internal_path) def key(self): @@ -3371,14 +3376,15 @@ def ui_image( if tex is not None: prop_input.label(text="Size: " + str(tex.size[0]) + " x " + str(tex.size[1])) - if not textureProp.use_tex_reference and textureProp.tex_format[:2] == "CI": + if is_hm64_feature_set() and not textureProp.use_tex_reference and textureProp.tex_format[:2] == "CI": row = prop_input.row(align=True) row.prop(textureProp, "custom_palette_name", text="TLUT Name") row = prop_input.row(align=True) row.prop(textureProp, "palette_color_count", text="Color Count") if not textureProp.use_tex_reference: - row = prop_input.row(align=True) - row.prop(textureProp, "is_vanilla_texture", text="Is Vanilla Texture?") + if is_hm64_feature_set(): + row = prop_input.row(align=True) + row.prop(textureProp, "is_vanilla_texture", text="Is Vanilla Texture?") row = prop_input.row(align=True) row.prop(textureProp, "texture_internal_path", text="Internal Path") @@ -5185,23 +5191,35 @@ def f3d_colors_from_dict(self, data: dict): def n64_colors_to_dict(self, use_dict: dict[str]): data = {} if use_dict["Environment"]: - data["environment"] = { + environment = { "set": self.set_env, "color": get_clean_color(self.env_color, include_alpha=True), - "dynamicEntry": self.env_dynamic_entry, - "dynamicEntryName": self.env_dynamic_entry_name, - "dynamicEntryCategory": self.env_dynamic_entry_category, } + if is_hm64_feature_set(): + environment.update( + { + "dynamicEntry": self.env_dynamic_entry, + "dynamicEntryName": self.env_dynamic_entry_name, + "dynamicEntryCategory": self.env_dynamic_entry_category, + } + ) + data["environment"] = environment if use_dict["Primitive"]: - data["primitive"] = { + primitive = { "set": self.set_prim, "color": get_clean_color(self.prim_color, include_alpha=True), "minLoDRatio": self.prim_lod_min, "loDFraction": self.prim_lod_frac, - "dynamicEntry": self.prim_dynamic_entry, - "dynamicEntryName": self.prim_dynamic_entry_name, - "dynamicEntryCategory": self.prim_dynamic_entry_category, } + if is_hm64_feature_set(): + primitive.update( + { + "dynamicEntry": self.prim_dynamic_entry, + "dynamicEntryName": self.prim_dynamic_entry_name, + "dynamicEntryCategory": self.prim_dynamic_entry_category, + } + ) + data["primitive"] = primitive if use_dict["Key"]: data["chromaKey"] = { "set": self.set_key, @@ -5233,9 +5251,10 @@ def n64_colors_from_dict(self, data: dict): self.set_env = enviroment.get("set", self.set_env) if "color" in enviroment: self.env_color = enviroment.get("color") - self.env_dynamic_entry = enviroment.get("dynamicEntry", self.env_dynamic_entry) - self.env_dynamic_entry_name = enviroment.get("dynamicEntryName", self.env_dynamic_entry_name) - self.env_dynamic_entry_category = enviroment.get("dynamicEntryCategory", self.env_dynamic_entry_category) + if is_hm64_feature_set(): + self.env_dynamic_entry = enviroment.get("dynamicEntry", self.env_dynamic_entry) + self.env_dynamic_entry_name = enviroment.get("dynamicEntryName", self.env_dynamic_entry_name) + self.env_dynamic_entry_category = enviroment.get("dynamicEntryCategory", self.env_dynamic_entry_category) primitive = data.get("primitive", {}) self.set_prim = primitive.get("set", self.set_prim) if "color" in primitive: @@ -5244,9 +5263,12 @@ def n64_colors_from_dict(self, data: dict): primitive.get("minLoDRatio", self.prim_lod_min), primitive.get("loDFraction", self.prim_lod_frac), ) - self.prim_dynamic_entry = primitive.get("dynamicEntry", self.prim_dynamic_entry) - self.prim_dynamic_entry_name = primitive.get("dynamicEntryName", self.prim_dynamic_entry_name) - self.prim_dynamic_entry_category = primitive.get("dynamicEntryCategory", self.prim_dynamic_entry_category) + if is_hm64_feature_set(): + self.prim_dynamic_entry = primitive.get("dynamicEntry", self.prim_dynamic_entry) + self.prim_dynamic_entry_name = primitive.get("dynamicEntryName", self.prim_dynamic_entry_name) + self.prim_dynamic_entry_category = primitive.get( + "dynamicEntryCategory", self.prim_dynamic_entry_category + ) key = data.get("chromaKey", {}) self.set_key = key.get("set", self.set_key) if "center" in key: @@ -5635,4 +5657,3 @@ def mat_unregister(): "Vertex Colored Texture (No Vertex Alpha)", ), ] - diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index a3a05c938..eaad22d73 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -420,7 +420,7 @@ def saveOrGetPaletteDefinition( if texProp and texProp.texture_internal_path: fPalette.internal_path = sanitize_internal_asset_path(texProp.texture_internal_path) if texProp: - fPalette.skip_export = texProp.is_vanilla_texture + fPalette.skip_export = is_hm64_feature_set() and texProp.is_vanilla_texture return paletteKey, fPalette paletteName, filename = getTextureNamesFromBasename( @@ -430,7 +430,7 @@ def saveOrGetPaletteDefinition( if texProp: fPalette.internal_path = sanitize_internal_asset_path(texProp.texture_internal_path) if texProp: - fPalette.skip_export = texProp.is_vanilla_texture + fPalette.skip_export = is_hm64_feature_set() and texProp.is_vanilla_texture parent.addTexture(paletteKey, fPalette, fMaterial) return paletteKey, fPalette @@ -461,7 +461,7 @@ def saveOrGetTextureDefinition( if texProp and texProp.texture_internal_path: fImage.internal_path = sanitize_internal_asset_path(texProp.texture_internal_path) if texProp: - fImage.skip_export = texProp.is_vanilla_texture + fImage.skip_export = is_hm64_feature_set() and texProp.is_vanilla_texture return imageKey, fImage imageName, filename = getTextureNamesFromProp(texProp, parent) @@ -470,7 +470,7 @@ def saveOrGetTextureDefinition( if texProp: fImage.internal_path = sanitize_internal_asset_path(texProp.texture_internal_path) if texProp: - fImage.skip_export = texProp.is_vanilla_texture + fImage.skip_export = is_hm64_feature_set() and texProp.is_vanilla_texture parent.addTexture(imageKey, fImage, fMaterial) return imageKey, fImage @@ -627,7 +627,7 @@ def getPaletteName(self): if not self.useTex or self.isPalRef: return None self.custom_palette_requested = False - if self.texProp is not None: + if is_hm64_feature_set() and self.texProp is not None: custom_name = getattr(self.texProp, "custom_palette_name", "") if custom_name: stripped = custom_name.strip() @@ -697,7 +697,11 @@ def writeAll( f3d = fModel.f3d palette_load_cmd = None if self.loadPal: - override = self.texProp.palette_color_count if self.texProp is not None else None + override = ( + self.texProp.palette_color_count + if is_hm64_feature_set() and self.texProp is not None + else None + ) palette_load_cmd = savePaletteLoad( loadGfx, fPalette, @@ -722,7 +726,9 @@ def writeAll( # Write texture data texProp = self.texProp - should_write_data = convertTextureData and not (texProp and texProp.is_vanilla_texture) + should_write_data = convertTextureData and not ( + is_hm64_feature_set() and texProp and texProp.is_vanilla_texture + ) if should_write_data: if self.isTexRef: if self.loadPal and not self.isPalRef: diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 2ce18f5ff..2a6c41f9f 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1466,8 +1466,16 @@ def saveOrGetF3DMaterial(material, fModel, _obj, drawLayer, convertTextureData): scaleToU8(f3dMat.prim_lod_min), scaleToU8(f3dMat.prim_lod_frac), *color, - cosmeticEntry=f3dMat.prim_dynamic_entry_name if f3dMat.prim_dynamic_entry else "", - cosmeticCategory=f3dMat.prim_dynamic_entry_category if f3dMat.prim_dynamic_entry else "", + cosmeticEntry=( + f3dMat.prim_dynamic_entry_name + if is_hm64_feature_set() and f3dMat.prim_dynamic_entry + else "" + ), + cosmeticCategory=( + f3dMat.prim_dynamic_entry_category + if is_hm64_feature_set() and f3dMat.prim_dynamic_entry + else "" + ), ) ) @@ -1476,8 +1484,16 @@ def saveOrGetF3DMaterial(material, fModel, _obj, drawLayer, convertTextureData): fMaterial.mat_only_DL.commands.append( DPSetEnvColor( *color, - cosmeticEntry=f3dMat.env_dynamic_entry_name if f3dMat.env_dynamic_entry else "", - cosmeticCategory=f3dMat.env_dynamic_entry_category if f3dMat.env_dynamic_entry else "", + cosmeticEntry=( + f3dMat.env_dynamic_entry_name + if is_hm64_feature_set() and f3dMat.env_dynamic_entry + else "" + ), + cosmeticCategory=( + f3dMat.env_dynamic_entry_category + if is_hm64_feature_set() and f3dMat.env_dynamic_entry + else "" + ), ) ) diff --git a/fast64_internal/hm64/__init__.py b/fast64_internal/hm64/__init__.py index f5061d17f..cb1916068 100644 --- a/fast64_internal/hm64/__init__.py +++ b/fast64_internal/hm64/__init__.py @@ -5,14 +5,18 @@ def hm64_register(): from .f3d.soh_xml_exporter import register as register_soh_xml from .z64.panels import register as register_z64_panels + from .mm.skeleton.operators import mm_skeleton_ops_register register_soh_xml() register_z64_panels() + mm_skeleton_ops_register() def hm64_unregister(): from .f3d.soh_xml_exporter import unregister as unregister_soh_xml from .z64.panels import unregister as unregister_z64_panels + from .mm.skeleton.operators import mm_skeleton_ops_unregister + mm_skeleton_ops_unregister() unregister_z64_panels() unregister_soh_xml() diff --git a/fast64_internal/hm64/mm/mm_f3d_writer.py b/fast64_internal/hm64/mm/mm_f3d_writer.py index 254cdd58b..c0d9ab81d 100644 --- a/fast64_internal/hm64/mm/mm_f3d_writer.py +++ b/fast64_internal/hm64/mm/mm_f3d_writer.py @@ -1471,8 +1471,16 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): scaleToU8(f3dMat.prim_lod_min), scaleToU8(f3dMat.prim_lod_frac), *color, - cosmeticEntry=f3dMat.prim_dynamic_entry_name if f3dMat.prim_dynamic_entry else "", - cosmeticCategory=f3dMat.prim_dynamic_entry_category if f3dMat.prim_dynamic_entry else "", + cosmeticEntry=( + f3dMat.prim_dynamic_entry_name + if is_hm64_feature_set() and f3dMat.prim_dynamic_entry + else "" + ), + cosmeticCategory=( + f3dMat.prim_dynamic_entry_category + if is_hm64_feature_set() and f3dMat.prim_dynamic_entry + else "" + ), ) ) @@ -1481,8 +1489,16 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): fMaterial.mat_only_DL.commands.append( DPSetEnvColor( *color, - cosmeticEntry=f3dMat.env_dynamic_entry_name if f3dMat.env_dynamic_entry else "", - cosmeticCategory=f3dMat.env_dynamic_entry_category if f3dMat.env_dynamic_entry else "", + cosmeticEntry=( + f3dMat.env_dynamic_entry_name + if is_hm64_feature_set() and f3dMat.env_dynamic_entry + else "" + ), + cosmeticCategory=( + f3dMat.env_dynamic_entry_category + if is_hm64_feature_set() and f3dMat.env_dynamic_entry + else "" + ), ) ) @@ -1993,4 +2009,3 @@ def f3d_writer_unregister(): unregister_class(cls) del bpy.types.Scene.matWriteMethod - diff --git a/fast64_internal/hm64/mm/skeleton/operators.py b/fast64_internal/hm64/mm/skeleton/operators.py index 85739fe80..a15d11282 100644 --- a/fast64_internal/hm64/mm/skeleton/operators.py +++ b/fast64_internal/hm64/mm/skeleton/operators.py @@ -6,7 +6,7 @@ from ....f3d.f3d_gbi import DLFormat from ....z64.skeleton.properties import OOTSkeletonExportSettings -from ....z64.utility import getOOTScale +from ....z64.utility import getOOTScale, is_hm64 from ....utility import ExportUtils, PluginError, raisePluginError from .functions import ootConvertArmatureToO2R @@ -16,6 +16,10 @@ class MM_ExportSkeleton(Operator): bl_label = "Export MM Skeleton" bl_options = {"REGISTER", "UNDO", "PRESET"} + @classmethod + def poll(cls, context): + return context.scene.gameEditorMode == "MM" and is_hm64() + def execute(self, context): with ExportUtils() as export_utils: armatureObj = None diff --git a/fast64_internal/hm64/z64/operators.py b/fast64_internal/hm64/z64/operators.py index 1347c9998..d51d12884 100644 --- a/fast64_internal/hm64/z64/operators.py +++ b/fast64_internal/hm64/z64/operators.py @@ -83,7 +83,7 @@ def ootConvertMeshToXML( ): folderName = settings.folder exportPath = resolve_custom_export_base(settings) - isCustomExport = settings.isCustom + isCustomExport = True name = resolve_dl_export_name(originalObj, settings) overlayName = settings.actorOverlayName flipbookUses2DArray = settings.flipbookUses2DArray diff --git a/fast64_internal/hm64/z64/panels.py b/fast64_internal/hm64/z64/panels.py index f0be288ef..dca45e911 100644 --- a/fast64_internal/hm64/z64/panels.py +++ b/fast64_internal/hm64/z64/panels.py @@ -1,10 +1,13 @@ """HM64 MM panels and matrix-call support classes extracted from z64/f3d/panels.py.""" import bpy -from bpy.types import Panel, Mesh, Operator, UIList +from bpy.props import CollectionProperty, IntProperty +from bpy.types import Object, Panel, Mesh, Operator, UIList from ...panels import MM_Panel +from ...z64.utility import is_hm64 from ...z64.f3d.properties import OOTDLExportSettings +from .properties import OOTDLMatrixCallPair class OOT_UL_MatrixCallPairs(UIList): @@ -23,7 +26,7 @@ class FAST64_OT_AddObjectMatrixCall(Operator): @classmethod def poll(cls, context): - return context.object is not None and isinstance(context.object.data, Mesh) + return is_hm64() and context.object is not None and isinstance(context.object.data, Mesh) def execute(self, context): obj = context.object @@ -44,7 +47,7 @@ class FAST64_OT_RemoveObjectMatrixCall(Operator): @classmethod def poll(cls, context): obj = context.object - return obj is not None and isinstance(obj.data, Mesh) and len(obj.oot_matrix_calls) > 0 + return is_hm64() and obj is not None and isinstance(obj.data, Mesh) and len(obj.oot_matrix_calls) > 0 def execute(self, context): obj = context.object @@ -64,7 +67,7 @@ class MM_DisplayListPanel(MM_Panel): @classmethod def poll(cls, context): - return context.scene.gameEditorMode == "MM" and ( + return is_hm64() and context.scene.gameEditorMode == "MM" and ( context.object is not None and isinstance(context.object.data, Mesh) ) @@ -83,7 +86,7 @@ class MM_MaterialPanel(MM_Panel): @classmethod def poll(cls, context): - return context.material is not None and context.scene.gameEditorMode == "MM" + return is_hm64() and context.material is not None and context.scene.gameEditorMode == "MM" def draw(self, context): from ...z64.f3d.panels import OOT_MaterialPanel @@ -100,7 +103,7 @@ class MM_DrawLayersPanel(MM_Panel): @classmethod def poll(cls, context): - return context.scene.gameEditorMode == "MM" + return is_hm64() and context.scene.gameEditorMode == "MM" def draw(self, context): from ...z64.f3d.panels import OOT_DrawLayersPanel @@ -111,6 +114,10 @@ class MM_ExportDLPanel(MM_Panel): bl_idname = "Z64_PT_export_dl_mm" bl_label = "DL Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): from ...z64.f3d.panels import OOT_ExportDLPanel OOT_ExportDLPanel.draw(self, context) @@ -124,6 +131,7 @@ def draw(self, context): ) hm64_support_classes = ( + OOTDLMatrixCallPair, OOT_UL_MatrixCallPairs, FAST64_OT_AddObjectMatrixCall, FAST64_OT_RemoveObjectMatrixCall, @@ -134,9 +142,13 @@ def register(): from bpy.utils import register_class for cls in (*hm64_panel_classes, *hm64_support_classes): register_class(cls) + Object.oot_matrix_calls = CollectionProperty(type=OOTDLMatrixCallPair) + Object.oot_matrix_calls_index = IntProperty(default=0) def unregister(): from bpy.utils import unregister_class + del Object.oot_matrix_calls + del Object.oot_matrix_calls_index for cls in reversed((*hm64_panel_classes, *hm64_support_classes)): unregister_class(cls) diff --git a/fast64_internal/hm64/z64/skeleton_xml.py b/fast64_internal/hm64/z64/skeleton_xml.py index 3f5c8ae5c..48f173c57 100644 --- a/fast64_internal/hm64/z64/skeleton_xml.py +++ b/fast64_internal/hm64/z64/skeleton_xml.py @@ -60,8 +60,13 @@ def ootConvertArmatureToXML( flipbookArrayIndex2D = settings.flipbookArrayIndex2D if flipbookUses2DArray else None isLink = False - exportPath = bpy.path.abspath(settings.customPath) - isCustomExport = settings.isCustom + customPath = (settings.customPath or "").strip() + if not customPath: + raise PluginError("Export path is empty.") + exportPath = bpy.path.abspath(customPath) + if not os.path.exists(exportPath): + os.makedirs(exportPath, exist_ok=True) + isCustomExport = True from ...z64.exporter.skeleton.functions import ootConvertArmatureToSkeletonWithMesh diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 5fc555572..b946ddce1 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -33,6 +33,13 @@ class VertexWeightError(PluginError): pass +def is_hm64_feature_set(): + scene = getattr(bpy.context, "scene", None) + fast64 = getattr(scene, "fast64", None) if scene is not None else None + oot = getattr(fast64, "oot", None) if fast64 is not None else None + return getattr(oot, "feature_set", None) == "hm64" + + class Matrix4x4Property(bpy.types.PropertyGroup): # blender's matrix subtype is broken :)))) row0: FloatVectorProperty(size=4, default=(1, 0, 0, 0)) row1: FloatVectorProperty(size=4, default=(0, 1, 0, 0)) diff --git a/fast64_internal/z64/__init__.py b/fast64_internal/z64/__init__.py index 89f93d775..a86b9d2d4 100644 --- a/fast64_internal/z64/__init__.py +++ b/fast64_internal/z64/__init__.py @@ -81,6 +81,7 @@ feature_set_enum = ( ("default", "Default", "Default"), ("hackeroot", "HackerOoT", "HackerOoT"), + ("hm64", "HM64", "HM64"), ) diff --git a/fast64_internal/z64/animated_mats/panels.py b/fast64_internal/z64/animated_mats/panels.py index e86a6ceeb..8c66b53d2 100644 --- a/fast64_internal/z64/animated_mats/panels.py +++ b/fast64_internal/z64/animated_mats/panels.py @@ -1,7 +1,7 @@ from bpy.utils import register_class, unregister_class from ...panels import MM_Panel, OOT_Panel -from ..utility import is_oot_features, is_hackeroot +from ..utility import is_oot_features, is_hackeroot, is_hm64 class Z64_AnimatedMaterialsPanel(OOT_Panel): @@ -23,6 +23,10 @@ class MM_AnimatedMaterialsPanel(MM_Panel): bl_idname = "Z64_PT_animated_materials_mm" bl_label = "Animated Materials Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): Z64_AnimatedMaterialsPanel.draw(self, context) diff --git a/fast64_internal/z64/animation/panels.py b/fast64_internal/z64/animation/panels.py index 17115f163..c94ec8f81 100644 --- a/fast64_internal/z64/animation/panels.py +++ b/fast64_internal/z64/animation/panels.py @@ -2,6 +2,7 @@ from bpy.utils import register_class, unregister_class from ...utility import prop_split from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 from .operators import OOT_ExportAnim, OOT_ImportAnim from .properties import OOTAnimExportSettingsProperty, OOTAnimImportSettingsProperty, OOTLinkTextureAnimProperty @@ -53,6 +54,10 @@ class MM_ExportAnimPanel(MM_Panel): bl_idname = "Z64_PT_export_anim_mm" bl_label = "Animation Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OOT_ExportAnimPanel.draw(self, context) diff --git a/fast64_internal/z64/collision/panels.py b/fast64_internal/z64/collision/panels.py index 69e254f77..dd26c98e2 100644 --- a/fast64_internal/z64/collision/panels.py +++ b/fast64_internal/z64/collision/panels.py @@ -1,6 +1,7 @@ from bpy.types import Panel, Camera from bpy.utils import register_class, unregister_class from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 from .properties import OOTCollisionExportSettings, OOTCameraPositionProperty, OOTMaterialCollisionProperty from .operators import OOT_ExportCollision @@ -62,6 +63,10 @@ class MM_ExportCollisionPanel(MM_Panel): bl_idname = "Z64_PT_export_collision_mm" bl_label = "Collision Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OOT_ExportCollisionPanel.draw(self, context) diff --git a/fast64_internal/z64/cutscene/motion/panels.py b/fast64_internal/z64/cutscene/motion/panels.py index eeed3af65..6c79be59f 100644 --- a/fast64_internal/z64/cutscene/motion/panels.py +++ b/fast64_internal/z64/cutscene/motion/panels.py @@ -1,5 +1,6 @@ from bpy.utils import register_class, unregister_class from ....panels import MM_Panel, OOT_Panel +from ...utility import is_hm64 from .properties import CutsceneCmdCameraShotProperty, CutsceneCmdCameraShotPointProperty @@ -48,6 +49,10 @@ class MM_CSMotionCameraShotPanel(MM_Panel): bl_context = "object" bl_options = {"HIDE_HEADER"} + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OOT_CSMotionCameraShotPanel.draw(self, context) diff --git a/fast64_internal/z64/cutscene/panels.py b/fast64_internal/z64/cutscene/panels.py index 72c0c6d8a..f52cf72a0 100644 --- a/fast64_internal/z64/cutscene/panels.py +++ b/fast64_internal/z64/cutscene/panels.py @@ -3,6 +3,7 @@ from bpy.props import BoolProperty from ...utility import prop_split from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 from .operators import OOT_ExportCutscene, OOT_ExportAllCutscenes, OOT_ImportCutscene @@ -65,6 +66,10 @@ class MM_OoT_PreviewSettingsPanel(MM_Panel): bl_idname = "Z64_PT_preview_settings_mm" bl_label = "CS Preview Settings" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OoT_PreviewSettingsPanel.draw(self, context) @@ -75,6 +80,10 @@ class MM_OOT_CutscenePanel(MM_Panel): bl_space_type = "VIEW_3D" bl_region_type = "UI" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OOT_CutscenePanel.draw(self, context) diff --git a/fast64_internal/z64/exporter/skeleton/__init__.py b/fast64_internal/z64/exporter/skeleton/__init__.py index dafa0fde1..3c2b6f594 100644 --- a/fast64_internal/z64/exporter/skeleton/__init__.py +++ b/fast64_internal/z64/exporter/skeleton/__init__.py @@ -1,2 +1 @@ -from .functions import ootConvertArmatureToSkeletonWithoutMesh, ootConvertArmatureToC -from ....hm64.z64.skeleton_xml import ootConvertArmatureToXML +from .functions import ootConvertArmatureToSkeletonWithoutMesh, ootConvertArmatureToC diff --git a/fast64_internal/z64/exporter/skeleton/functions.py b/fast64_internal/z64/exporter/skeleton/functions.py index e5b97590b..f60219a1f 100644 --- a/fast64_internal/z64/exporter/skeleton/functions.py +++ b/fast64_internal/z64/exporter/skeleton/functions.py @@ -9,19 +9,16 @@ from ...model_classes import OOTModel, OOTGfxFormatter from ...skeleton.constants import ootSkeletonImportDict from ...skeleton.properties import OOTSkeletonExportSettings -from ...skeleton.utility import ootDuplicateArmatureAndRemoveRotations, getGroupIndices -from .classes import OOTDLReference, OOTLimb, OOTSkeleton +from ...skeleton.utility import ootDuplicateArmatureAndRemoveRotations, getGroupIndices, ootRemoveSkeleton +from .classes import OOTLimb, OOTSkeleton from ....utility import ( PluginError, CData, getGroupIndexFromname, writeCData, - writeXMLData, toAlnum, cleanupDuplicatedObjects, - get_internal_asset_path, - sanitize_internal_asset_path, ) from ...utility import ( @@ -33,19 +30,6 @@ addIncludeFiles, ) -from ....hm64.z64.skeleton_xml import ootConvertArmatureToXML - - -def _normalize_folder_for_path( - folderName: str, keep_objects_prefix: bool = False, ensure_objects_prefix: bool = False -) -> str: - folder_path = sanitize_internal_asset_path(folderName) - if folder_path.startswith("objects/") and not keep_objects_prefix: - folder_path = folder_path[len("objects/") :] - if ensure_objects_prefix and folder_path and not folder_path.startswith("objects/"): - folder_path = "objects/" + folder_path - return folder_path - def ootProcessBone( fModel, @@ -85,7 +69,7 @@ def ootProcessBone( boneName, convertTransformMatrix, armatureObj, - "", + namePrefix, meshInfo, drawLayer, convertTextureData, @@ -112,10 +96,6 @@ def ootProcessBone( ) DL = mesh.draw - if DL is None: - # Maintain a placeholder DL when geometry was removed or overridden. - DL = OOTDLReference("gEmptyDL") - if isinstance(parentLimb, OOTSkeleton): skeleton = parentLimb limb = OOTLimb(skeleton.name, boneName, nextIndex, translate, DL, None) @@ -239,9 +219,10 @@ def ootConvertArmatureToC( drawLayer: str, settings: OOTSkeletonExportSettings, ): - if settings.mode != "Generic": + if settings.mode != "Generic" and not settings.isCustom: importInfo = ootSkeletonImportDict[settings.mode] skeletonName = importInfo.skeletonName + filename = skeletonName folderName = importInfo.folderName overlayName = importInfo.actorOverlayName flipbookUses2DArray = importInfo.flipbookArrayIndex2D is not None @@ -249,20 +230,21 @@ def ootConvertArmatureToC( isLink = importInfo.isLink else: skeletonName = toAlnum(originalArmatureObj.name) + filename = settings.filename if settings.isCustomFilename else skeletonName folderName = settings.folder - overlayName = settings.actorOverlayName + overlayName = settings.actorOverlayName if not settings.isCustom else None flipbookUses2DArray = settings.flipbookUses2DArray flipbookArrayIndex2D = settings.flipbookArrayIndex2D if flipbookUses2DArray else None isLink = False - filename = skeletonName - exportPath = bpy.path.abspath(settings.customPath) isCustomExport = settings.isCustom + removeVanillaData = settings.removeVanillaData + optimize = settings.optimize fModel = OOTModel(skeletonName, DLFormat, drawLayer) skeleton, fModel = ootConvertArmatureToSkeletonWithMesh( - originalArmatureObj, convertTransformMatrix, fModel, skeletonName, not savePNG, drawLayer, False + originalArmatureObj, convertTransformMatrix, fModel, skeletonName, not savePNG, drawLayer, optimize ) if originalArmatureObj.ootSkeleton.LOD is not None: @@ -273,7 +255,7 @@ def ootConvertArmatureToC( skeletonName + "_lod", not savePNG, drawLayer, - False, + optimize, ) else: lodSkeleton = None @@ -313,28 +295,8 @@ def ootConvertArmatureToC( else: data.header += "\n" - data.header = f"#ifndef {header_filename.upper()}_H\n" + f"#define {header_filename.upper()}_H\n\n" - - if bpy.context.scene.fast64.oot.is_globalh_present(): - data.header += '#include "ultra64.h"\n' + '#include "global.h"\n' - elif bpy.context.scene.fast64.oot.is_z64sceneh_present(): - data.header += '#include "ultra64.h"\n' + '#include "array_count.h"\n' + '#include "z64animation.h"\n' - else: - data.header += '#include "ultra64.h"\n' + '#include "array_count.h"\n' + '#include "animation.h"\n' - - data.source = f'#include "{header_filename}.h"\n\n' - if not isCustomExport: - data.header += f'#include "{folderName}.h"\n\n' - else: - data.header += "\n" - - folder_path_for_export = _normalize_folder_for_path( - folderName, keep_objects_prefix=isCustomExport, ensure_objects_prefix=isCustomExport - ) - if not folder_path_for_export: - folder_path_for_export = sanitize_internal_asset_path(folderName) - path = ootGetPath(exportPath, isCustomExport, "assets/objects/", folder_path_for_export, True, True) - includeDir = get_internal_asset_path(settings, folderName) + path = ootGetPath(exportPath, isCustomExport, "assets/objects/", folderName, True, True) + includeDir = settings.customAssetIncludeDir if settings.isCustom else f"assets/objects/{folderName}" exportData = fModel.to_c( TextureExportSettings(False, savePNG, includeDir, path), OOTGfxFormatter(ScrollMethod.Vertex) ) @@ -353,3 +315,5 @@ def ootConvertArmatureToC( if not isCustomExport: writeTextureArraysExisting(bpy.context.scene.ootDecompPath, overlayName, isLink, flipbookArrayIndex2D, fModel) addIncludeFiles(folderName, path, filename) + if removeVanillaData: + ootRemoveSkeleton(path, folderName, skeletonName) diff --git a/fast64_internal/z64/f3d/operators.py b/fast64_internal/z64/f3d/operators.py index 170f60b45..50fef3a68 100644 --- a/fast64_internal/z64/f3d/operators.py +++ b/fast64_internal/z64/f3d/operators.py @@ -10,32 +10,24 @@ from mathutils import Matrix from typing import Optional -from ...utility import CData, PluginError, ExportUtils, raisePluginError, writeCData, writeXMLData, toAlnum +from ...utility import CData, PluginError, ExportUtils, raisePluginError, writeCData, toAlnum from ...f3d.f3d_parser import importMeshC, getImportData from ...f3d.f3d_gbi import DLFormat, TextureExportSettings, ScrollMethod, get_F3D_GBI from ...f3d.f3d_writer import TriangleConverterInfo, removeDL, saveStaticModel, getInfoDict -from ..utility import ootGetObjectPath, ootGetObjectHeaderPath, getOOTScale, checkEmptyName +from ..utility import ootGetObjectPath, ootGetObjectHeaderPath, getOOTScale, is_hm64 from ..model_classes import OOTF3DContext, ootGetIncludedAssetData from ..texture_array import ootReadTextureArrays from ..model_classes import OOTModel, OOTGfxFormatter from ..f3d_writer import ootReadActorScale, writeTextureArraysNew, writeTextureArraysExisting -from .properties import OOTDLImportSettings, OOTDLExportSettings, LIMB_MATRIX_PATHS +from .properties import OOTDLImportSettings, OOTDLExportSettings from ..utility import ( OOTObjectCategorizer, ootDuplicateHierarchy, ootCleanupScene, + ootGetPath, addIncludeFiles, - get_internal_asset_path, -) - -from ...hm64.z64.operators import ( - build_extra_xml_entries, - get_active_matrix_entries, - resolve_custom_export_base, - resolve_custom_export_folder, - resolve_dl_export_name, - ootConvertMeshToXML, + getOOTScale, ) @@ -56,10 +48,16 @@ def ootConvertMeshToC( settings: OOTDLExportSettings, ): folderName = settings.folder - exportPath = resolve_custom_export_base(settings) + exportPath = bpy.path.abspath(settings.customPath) isCustomExport = settings.isCustom removeVanillaData = settings.removeVanillaData - name = resolve_dl_export_name(originalObj, settings) + + obj_name = toAlnum(originalObj.name) + assert obj_name is not None + + filename = toAlnum(settings.filename) if settings.isCustomFilename else obj_name + assert filename is not None + overlayName = settings.actorOverlayName flipbookUses2DArray = settings.flipbookUses2DArray flipbookArrayIndex2D = settings.flipbookArrayIndex2D if flipbookUses2DArray else None @@ -67,7 +65,7 @@ def ootConvertMeshToC( try: obj, allObjs = ootDuplicateHierarchy(originalObj, None, False, OOTObjectCategorizer()) - fModel = OOTModel(name, DLFormat, None) + fModel = OOTModel(obj_name, DLFormat, None) triConverterInfo = TriangleConverterInfo(obj, None, fModel.f3d, finalTransform, getInfoDict(obj)) fMeshes = saveStaticModel( triConverterInfo, fModel, obj, finalTransform, fModel.name, not saveTextures, False, "oot" @@ -75,7 +73,7 @@ def ootConvertMeshToC( # Since we provide a draw layer override, there should only be one fMesh. for fMesh in fMeshes.values(): - fMesh.draw.name = name + fMesh.draw.name = obj_name ootCleanupScene(originalObj, allObjs) @@ -83,7 +81,6 @@ def ootConvertMeshToC( ootCleanupScene(originalObj, allObjs) raise Exception(str(e)) - filename = settings.filename if settings.isCustomFilename else name data = CData() data.header = f"#ifndef {filename.upper()}_H\n" + f"#define {filename.upper()}_H\n\n" + '#include "ultra64.h"\n' @@ -96,8 +93,8 @@ def ootConvertMeshToC( else: data.header += "\n" - path = resolve_custom_export_folder(exportPath, folderName) - includeDir = get_internal_asset_path(settings, folderName) + path = ootGetPath(exportPath, isCustomExport, "assets/objects/", folderName, False, True) + includeDir = settings.customAssetIncludeDir if settings.isCustom else f"assets/objects/{folderName}" exportData = fModel.to_c( TextureExportSettings(False, saveTextures, includeDir, path), OOTF3DGfxFormatter(ScrollMethod.Vertex) ) @@ -113,11 +110,11 @@ def ootConvertMeshToC( if not isCustomExport: writeTextureArraysExisting(bpy.context.scene.ootDecompPath, overlayName, False, flipbookArrayIndex2D, fModel) - addIncludeFiles(folderName, path, name) + addIncludeFiles(folderName, path, filename) if removeVanillaData: headerPath = os.path.join(path, folderName + ".h") sourcePath = os.path.join(path, folderName + ".c") - removeDL(sourcePath, headerPath, name) + removeDL(sourcePath, headerPath, filename) class OOT_ImportDL(Operator): @@ -175,7 +172,17 @@ def execute(self, context): scale = None if not isCustomImport: - filedata = ootGetIncludedAssetData(basePath, paths, filedata) + filedata + filedata = ( + ootGetIncludedAssetData( + [ + basePath, + str(Path(basePath) / context.scene.fast64.oot.get_extracted_path()), + ], + paths, + filedata, + ) + + filedata + ) if overlayName is not None: ootReadTextureArrays(basePath, overlayName, name, f3dContext, False, flipbookArrayIndex2D) @@ -207,12 +214,16 @@ def execute(self, context): class OOT_ExportDL(Operator): + # set bl_ properties bl_idname = "object.oot_export_dl" bl_label = "Export DL" bl_options = {"REGISTER", "UNDO", "PRESET"} + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) def execute(self, context): with ExportUtils() as export_utils: + obj = None if context.mode != "OBJECT": object.mode_set(mode="OBJECT") if len(context.selected_objects) == 0: @@ -224,16 +235,31 @@ def execute(self, context): finalTransform = Matrix.Scale(getOOTScale(obj.ootActorScale), 4) try: + # exportPath, levelName = getPathAndLevel(context.scene.geoCustomExport, + # context.scene.geoExportPath, context.scene.geoLevelName, + # context.scene.geoLevelOption) + saveTextures = context.scene.saveTextures exportSettings = context.scene.fast64.oot.DLExportSettings - ootConvertMeshToXML( - obj, - finalTransform, - DLFormat.Static, - saveTextures, - exportSettings, - ) + if is_hm64(): + from ...hm64.z64.operators import ootConvertMeshToXML + + ootConvertMeshToXML( + obj, + finalTransform, + DLFormat.Static, + saveTextures, + exportSettings, + ) + else: + ootConvertMeshToC( + obj, + finalTransform, + DLFormat.Static, + saveTextures, + exportSettings, + ) self.report({"INFO"}, "Success!") return {"FINISHED"} diff --git a/fast64_internal/z64/f3d/properties.py b/fast64_internal/z64/f3d/properties.py index 3bae0526a..30135b8d4 100644 --- a/fast64_internal/z64/f3d/properties.py +++ b/fast64_internal/z64/f3d/properties.py @@ -1,15 +1,13 @@ import bpy from bpy.types import PropertyGroup, Object, World, Material, UILayout, Mesh -from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty, CollectionProperty +from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty from bpy.utils import register_class, unregister_class from ...f3d.f3d_material import update_world_default_rendermode from ...f3d.f3d_parser import ootEnumDrawLayers from ...utility import prop_split -from ..utility import is_hackeroot - -from ...hm64.z64.properties import LIMB_MATRIX_OPTIONS, LIMB_MATRIX_PATHS, OOTDLMatrixCallPair +from ..utility import is_hackeroot, is_hm64 class OOTDLExportSettings(PropertyGroup): @@ -21,12 +19,10 @@ class OOTDLExportSettings(PropertyGroup): name="Use Custom DL Name", description="Use a custom DL name instead of the object name" ) customDLName: StringProperty(name="DL Name") - folder: StringProperty(name="DL Folder", default="objects/gameplay_keep") + folder: StringProperty(name="DL Folder", default="gameplay_keep") customPath: StringProperty(name="Custom DL Path", subtype="FILE_PATH") isCustom: BoolProperty( - name="Use Custom Path", - description="Determines whether or not to export to an explicitly specified folder", - default=True, + name="Use Custom Path", description="Determines whether or not to export to an explicitly specified folder" ) removeVanillaData: BoolProperty(name="Replace Vanilla DLs") actorOverlayName: StringProperty(name="Overlay", default="") @@ -36,33 +32,53 @@ class OOTDLExportSettings(PropertyGroup): name="Asset Include Directory", default="assets/objects/gameplay_keep", description="Used in #include for including image files", - ) + ) def draw_props(self, layout: UILayout, context: bpy.types.Context | None = None): - layout.prop(self, "useCustomDLName") - if self.useCustomDLName: - prop_split(layout, self, "customDLName", "DL Name") - prop_split(layout, self, "folder", "Internal Path") - prop_split(layout, self, "customPath", "Path") - prop_split(layout, self, "actorOverlayName", "Overlay (Optional)") - owner_info = self._determine_matrix_owner(context) - if owner_info: - self._draw_matrix_call_section(layout, *owner_info) + if is_hm64(): + layout.prop(self, "useCustomDLName") + if self.useCustomDLName: + prop_split(layout, self, "customDLName", "DL Name") + prop_split(layout, self, "folder", "Internal Path") + prop_split(layout, self, "customPath", "Path") + prop_split(layout, self, "actorOverlayName", "Overlay (Optional)") + owner_info = self._determine_matrix_owner(context) + if owner_info: + self._draw_matrix_call_section(layout, *owner_info) + return + + layout.label(text="Object name used for export.", icon="INFO") + layout.prop(self, "isCustomFilename") + if self.isCustomFilename: + prop_split(layout, self, "filename", "Filename") + prop_split(layout, self, "folder", "Object" if not self.isCustom else "Folder") + if self.isCustom: + prop_split(layout, self, "customAssetIncludeDir", "Asset Include Path") + prop_split(layout, self, "customPath", "Path") + else: + prop_split(layout, self, "actorOverlayName", "Overlay (Optional)") + layout.prop(self, "flipbookUses2DArray") + if self.flipbookUses2DArray: + box = layout.box().column() + prop_split(box, self, "flipbookArrayIndex2D", "Flipbook Index") + + layout.prop(self, "isCustom") + layout.prop(self, "removeVanillaData") def _determine_matrix_owner( - self, context: bpy.types.Context | None - ) -> tuple[object, str, str, str, str, str] | None: - obj = context.object if context else None - if obj is not None and isinstance(obj.data, Mesh): - return ( - obj, - "oot_matrix_calls", - "oot_matrix_calls_index", - "fast64.oot_add_object_matrix_call", - "fast64.oot_remove_object_matrix_call", - f"Matrix Path + CallDisplayList ({obj.name})", - ) - return None + self, context: bpy.types.Context | None + ) -> tuple[object, str, str, str, str, str] | None: + obj = context.object if context else None + if obj is not None and isinstance(obj.data, Mesh): + return ( + obj, + "oot_matrix_calls", + "oot_matrix_calls_index", + "fast64.oot_add_object_matrix_call", + "fast64.oot_remove_object_matrix_call", + f"Matrix Path + CallDisplayList ({obj.name})", + ) + return None def _draw_matrix_call_section( self, @@ -227,7 +243,6 @@ def draw_props(self, layout: UILayout): oot_dl_writer_classes = ( - OOTDLMatrixCallPair, OOTDLExportSettings, OOTDLImportSettings, OOTDynamicMaterialDrawLayerProperty, @@ -246,8 +261,6 @@ def f3d_props_register(): register_class(cls) Object.ootDrawLayer = EnumProperty(items=ootEnumDrawLayers, default="Opaque") - Object.oot_matrix_calls = CollectionProperty(type=OOTDLMatrixCallPair) - Object.oot_matrix_calls_index = IntProperty(default=0) # Doesn't work since all static meshes are pre-transformed # Object.ootDynamicTransform = PointerProperty(type = OOTDynamicTransformProperty) @@ -262,5 +275,3 @@ def f3d_props_unregister(): del Material.ootMaterial del Object.ootObjectMenu - del Object.oot_matrix_calls - del Object.oot_matrix_calls_index diff --git a/fast64_internal/z64/file_settings.py b/fast64_internal/z64/file_settings.py index 6a9afbdf8..f43ba964b 100644 --- a/fast64_internal/z64/file_settings.py +++ b/fast64_internal/z64/file_settings.py @@ -6,6 +6,7 @@ from ..utility import prop_split from ..render_settings import on_update_render_settings from ..panels import MM_Panel, OOT_Panel +from .utility import is_hm64 class OOT_FileSettingsPanel(OOT_Panel): @@ -50,6 +51,10 @@ class MM_FileSettingsPanel(MM_Panel): bl_label = "Workspace Settings" bl_options = set() + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OOT_FileSettingsPanel.draw(self, context) diff --git a/fast64_internal/z64/hackeroot/panels.py b/fast64_internal/z64/hackeroot/panels.py index 6a234b53e..0e084fed5 100644 --- a/fast64_internal/z64/hackeroot/panels.py +++ b/fast64_internal/z64/hackeroot/panels.py @@ -1,6 +1,7 @@ from bpy.utils import register_class, unregister_class from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 class HackerOoTSettingsPanel(OOT_Panel): @@ -21,6 +22,10 @@ class MM_HackerOoTSettingsPanel(MM_Panel): bl_idname = "Z64_PT_hackeroot_settings_mm" bl_label = "HackerOoT Settings" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): HackerOoTSettingsPanel.draw(self, context) diff --git a/fast64_internal/z64/scene/panels.py b/fast64_internal/z64/scene/panels.py index 8a323797a..c91f8c988 100644 --- a/fast64_internal/z64/scene/panels.py +++ b/fast64_internal/z64/scene/panels.py @@ -2,7 +2,7 @@ from bpy.utils import register_class, unregister_class from ...panels import MM_Panel, OOT_Panel from ..constants import ootEnumSceneID -from ..utility import getEnumName +from ..utility import getEnumName, is_hm64 from .properties import ( OOTExportSceneSettingsProperty, OOTImportSceneSettingsProperty, @@ -68,6 +68,10 @@ class MM_ExportScenePanel(MM_Panel): bl_idname = "Z64_PT_export_level_mm" bl_label = "Scene Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def drawSceneSearchOp(self, layout: UILayout, enumValue: str, opName: str): OOT_ExportScenePanel.drawSceneSearchOp(self, layout, enumValue, opName) diff --git a/fast64_internal/z64/skeleton/constants.py b/fast64_internal/z64/skeleton/constants.py index 5c29445d8..f4c90aa1c 100644 --- a/fast64_internal/z64/skeleton/constants.py +++ b/fast64_internal/z64/skeleton/constants.py @@ -284,6 +284,14 @@ def get_skeleton_import_dict(game_mode: str | None) -> OrderedDict[str, OOTSkele return mmSkeletonImportDict if game_mode == "MM" else ootSkeletonImportDict +ootEnumSkeletonImportMode = [ + ("Generic", "Generic", "Generic"), +] + +for name, info in ootSkeletonImportDict.items(): + ootEnumSkeletonImportMode.append((name, name, name)) + + def find_skeleton_import_info(mode: str, game_mode: str | None) -> OOTSkeletonImportInfo | None: import_dict = get_skeleton_import_dict(game_mode) return import_dict.get(mode) diff --git a/fast64_internal/z64/skeleton/operators.py b/fast64_internal/z64/skeleton/operators.py index 65812ee1f..31276ea0e 100644 --- a/fast64_internal/z64/skeleton/operators.py +++ b/fast64_internal/z64/skeleton/operators.py @@ -5,11 +5,10 @@ from mathutils import Matrix from ...f3d.f3d_gbi import DLFormat from ...utility import PluginError, ExportUtils, raisePluginError -from ..utility import getStartBone, getNextBone, getOOTScale -from ..exporter.skeleton import ootConvertArmatureToXML +from ..utility import getStartBone, getNextBone, getOOTScale, is_hm64 +from ..exporter.skeleton import ootConvertArmatureToC from .importer import ootImportSkeletonC from .properties import OOTSkeletonImportSettings, OOTSkeletonExportSettings -from ...hm64.mm.skeleton.operators import mm_skeleton_ops_register, mm_skeleton_ops_unregister, MM_ExportSkeleton # Copy data from console into python file @@ -124,9 +123,16 @@ def execute(self, context): saveTextures = context.scene.saveTextures drawLayer = armatureObj.ootDrawLayer - ootConvertArmatureToXML( - armatureObj, finalTransform, DLFormat.Static, saveTextures, drawLayer, exportSettings - ) + if is_hm64(): + from ...hm64.z64.skeleton_xml import ootConvertArmatureToXML + + ootConvertArmatureToXML( + armatureObj, finalTransform, DLFormat.Static, saveTextures, drawLayer, exportSettings + ) + else: + ootConvertArmatureToC( + armatureObj, finalTransform, DLFormat.Static, saveTextures, drawLayer, exportSettings + ) self.report({"INFO"}, "Success!") return {"FINISHED"} @@ -148,10 +154,8 @@ def execute(self, context): def skeleton_ops_register(): for cls in oot_skeleton_classes: register_class(cls) - mm_skeleton_ops_register() def skeleton_ops_unregister(): - mm_skeleton_ops_unregister() for cls in reversed(oot_skeleton_classes): unregister_class(cls) diff --git a/fast64_internal/z64/skeleton/panels.py b/fast64_internal/z64/skeleton/panels.py index e898e6c9b..d1bf5401d 100644 --- a/fast64_internal/z64/skeleton/panels.py +++ b/fast64_internal/z64/skeleton/panels.py @@ -2,6 +2,7 @@ from bpy.utils import register_class, unregister_class from ...utility import prop_split from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 from .properties import OOTSkeletonImportSettings, OOTSkeletonExportSettings from .operators import OOT_ImportSkeleton, OOT_ExportSkeleton @@ -52,9 +53,6 @@ def draw(self, context): context.bone.ootBone.draw_props(col) -from ...hm64.mm.skeleton.operators import MM_ExportSkeleton - - class OOT_ExportSkeletonPanel(OOT_Panel): bl_idname = "Z64_PT_export_skeleton" bl_label = "Skeleton Exporter" @@ -75,7 +73,13 @@ class MM_ExportSkeletonPanel(MM_Panel): bl_idname = "Z64_PT_export_skeleton_mm" bl_label = "MM Skeleton Exporter" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): + from ...hm64.mm.skeleton.operators import MM_ExportSkeleton + col = self.layout.column() col.operator(MM_ExportSkeleton.bl_idname) exportSettings: OOTSkeletonExportSettings = context.scene.fast64.oot.skeletonExportSettings diff --git a/fast64_internal/z64/skeleton/properties.py b/fast64_internal/z64/skeleton/properties.py index ffd4ac35e..f4d8784f3 100644 --- a/fast64_internal/z64/skeleton/properties.py +++ b/fast64_internal/z64/skeleton/properties.py @@ -5,7 +5,8 @@ from bpy.utils import register_class, unregister_class from ...f3d.f3d_material import ootEnumDrawLayers from ...utility import prop_split -from .constants import get_skeleton_mode_items +from ..utility import is_hm64 +from .constants import ootEnumSkeletonImportMode ootEnumBoneType = [ @@ -52,34 +53,69 @@ def draw_props(self, layout: UILayout): class OOTSkeletonExportSettings(PropertyGroup): - mode: EnumProperty(name="Mode", items=get_skeleton_mode_items) - folder: StringProperty(name="Skeleton Folder", default="objects/object_geldb") + isCustomFilename: BoolProperty( + name="Use Custom Filename", description="Override filename instead of basing it off of the Blender name" + ) + filename: StringProperty(name="Filename") + mode: EnumProperty(name="Mode", items=ootEnumSkeletonImportMode) + folder: StringProperty(name="Skeleton Folder", default="object_geldb") customPath: StringProperty(name="Custom Skeleton Path", subtype="FILE_PATH") isCustom: BoolProperty( - name="Use Custom Path", - description="Determines whether or not to export to an explicitly specified folder", - default=True, + name="Use Custom Path", description="Determines whether or not to export to an explicitly specified folder" ) - filename: StringProperty(name="File Name", default="") - isCustomFilename: BoolProperty(name="Custom File Name", default=False) - removeVanillaData: BoolProperty(name="Replace Vanilla Skeletons On Export", default=False) - optimize: BoolProperty(name="Optimize Skeleton Export", default=False) + removeVanillaData: BoolProperty(name="Replace Vanilla Skeletons On Export", default=True) actorOverlayName: StringProperty(name="Overlay", default="ovl_En_GeldB") flipbookUses2DArray: BoolProperty(name="Has 2D Flipbook Array", default=False) flipbookArrayIndex2D: IntProperty(name="Index if 2D Array", default=0, min=0) customAssetIncludeDir: StringProperty( name="Asset Include Directory", default="assets/objects/object_geldb", - description="Legacy include path storage (fallback for compatibility).", + description="Used in #include for including image files", + ) + optimize: BoolProperty( + name="Optimize", + description="Applies various optimizations between the limbs in a skeleton. " + + "If enabled, the skeleton limbs must be drawn in their normal order, " + + "with nothing in between and no culling, otherwise the mesh will be corrupted.", ) def draw_props(self, layout: UILayout): - prop_split(layout, self, "folder", "Internal Path") - prop_split(layout, self, "customPath", "Path") + if is_hm64(): + prop_split(layout, self, "folder", "Internal Path") + prop_split(layout, self, "customPath", "Path") + return + + layout.prop(self, "removeVanillaData") + layout.prop(self, "optimize") + if self.optimize: + b = layout.box().column() + b.label(icon="LIBRARY_DATA_BROKEN", text="Do not draw anything in SkelAnime") + b.label(text="callbacks or cull limbs, will be corrupted.") + layout.prop(self, "isCustom") + layout.label(text="Object name used for export.", icon="INFO") + layout.prop(self, "isCustomFilename") + if self.isCustomFilename: + prop_split(layout, self, "filename", "Filename") + if self.isCustom: + prop_split(layout, self, "folder", "Object" if not self.isCustom else "Folder") + prop_split(layout, self, "customAssetIncludeDir", "Asset Include Path") + prop_split(layout, self, "customPath", "Path") + else: + prop_split(layout, self, "mode", "Mode") + if self.mode == "Generic": + prop_split(layout, self, "folder", "Object" if not self.isCustom else "Folder") + prop_split(layout, self, "actorOverlayName", "Overlay") + layout.prop(self, "flipbookUses2DArray") + if self.flipbookUses2DArray: + box = layout.box().column() + prop_split(box, self, "flipbookArrayIndex2D", "Flipbook Index") + elif self.mode == "Adult Link" or self.mode == "Child Link": + layout.label(text="Requires enabling NON_MATCHING in Makefile.", icon="ERROR") + layout.label(text="Preserve all bone deform toggles if modifying an imported skeleton.", icon="ERROR") class OOTSkeletonImportSettings(PropertyGroup): - mode: EnumProperty(name="Mode", items=get_skeleton_mode_items) + mode: EnumProperty(name="Mode", items=ootEnumSkeletonImportMode) applyRestPose: BoolProperty(name="Apply Friendly Rest Pose (If Available)", default=True) name: StringProperty(name="Skeleton Name", default="gGerudoRedSkel") folder: StringProperty(name="Skeleton Folder", default="object_geldb") diff --git a/fast64_internal/z64/tools/panel.py b/fast64_internal/z64/tools/panel.py index 9c1cc8fce..ee99a2781 100644 --- a/fast64_internal/z64/tools/panel.py +++ b/fast64_internal/z64/tools/panel.py @@ -1,5 +1,6 @@ from bpy.utils import register_class, unregister_class from ...panels import MM_Panel, OOT_Panel +from ..utility import is_hm64 from .operators import ( OOT_AddWaterBox, OOT_AddDoor, @@ -34,6 +35,10 @@ class MM_OoT_ToolsPanel(MM_Panel): bl_idname = "Z64_PT_tools_mm" bl_label = "Tools" + @classmethod + def poll(cls, context): + return MM_Panel.poll(context) and is_hm64() + def draw(self, context): OoT_ToolsPanel.draw(self, context) diff --git a/fast64_internal/z64/utility.py b/fast64_internal/z64/utility.py index e8151fd51..5fac81d18 100644 --- a/fast64_internal/z64/utility.py +++ b/fast64_internal/z64/utility.py @@ -1041,6 +1041,10 @@ def is_hackeroot(): return game_data.z64.is_oot() and bpy.context.scene.fast64.oot.feature_set == "hackeroot" +def is_hm64(): + return bpy.context.scene.fast64.oot.feature_set == "hm64" + + def add_include_to_spec_segment(spec_p: Path, segment: str, inc: str): spec_content = spec_p.read_text() new_spec_lines = []