diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 890176c34..950e8e50a 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -92,16 +92,9 @@ } -sm64EnumDrawLayers = [ - ("0", "Background (0x00)", "Background"), - ("1", "Opaque (0x01)", "Opaque"), - ("2", "Opaque Decal (0x02)", "Opaque Decal"), - ("3", "Opaque Intersecting (0x03)", "Opaque Intersecting"), - ("4", "Cutout (0x04)", "Cutout"), - ("5", "Transparent (0x05)", "Transparent"), - ("6", "Transparent Decal (0x06)", "Transparent Decal"), - ("7", "Transparent Intersecting (0x07)", "Transparent Intersecting"), -] +def get_sm64_draw_layers(_self, context): + return context.scene.fast64.sm64.draw_layers.to_enum() + ootEnumDrawLayers = [ ("Opaque", "Opaque", "Opaque"), @@ -109,22 +102,15 @@ ("Overlay", "Overlay", "Overlay"), ] - -drawLayerSM64toOOT = { - "0": "Opaque", - "1": "Opaque", - "2": "Opaque", - "3": "Opaque", - "4": "Opaque", - "5": "Transparent", - "6": "Transparent", - "7": "Transparent", -} - -drawLayerOOTtoSM64 = { - "Opaque": "1", - "Transparent": "5", - "Overlay": "1", +drawLayerSM64Alpha = { + "0": "OPA", + "1": "OPA", + "2": "OPA", + "3": "OPA", + "4": "CLIP", + "5": "XLU", + "6": "XLU", + "7": "XLU", } @@ -229,34 +215,32 @@ def update_draw_layer(self, context): if not material: return - drawLayer = material.f3d_mat.draw_layer - if context.scene.gameEditorMode == "SM64": - drawLayer.oot = drawLayerSM64toOOT[drawLayer.sm64] - elif context.scene.gameEditorMode in {"OOT", "MM"}: - if material.f3d_mat.draw_layer.oot == "Opaque": - if int(material.f3d_mat.draw_layer.sm64) > 4: - material.f3d_mat.draw_layer.sm64 = "1" - elif material.f3d_mat.draw_layer.oot == "Transparent": - if int(material.f3d_mat.draw_layer.sm64) < 5: - material.f3d_mat.draw_layer.sm64 = "5" material.f3d_mat.presetName = "Custom" update_blend_method(material, context) + update_fog_nodes(material, context) set_output_node_groups(material) + drawLayer = material.f3d_mat.draw_layer + output_method = get_output_method(material) + if context.scene.gameEditorMode == "SM64": + drawLayer.oot = {"OPA": "Opaque", "XLU": "Transparent"}.get(output_method, "Opaque") + elif context.scene.gameEditorMode == "OOT": + drawLayer.sm64 = {"OPA": "1", "XLU": "5"}.get(output_method, "1") # expects vanilla draw layers + def get_world_layer_defaults(scene, game_mode: str, layer: str): - world = scene.world - if world is None: - return default_draw_layers.get(game_mode, {}).get(layer, ("", "")) + default = default_draw_layers.get(game_mode, {}).get(layer, ("", "")) if game_mode == "SM64": - return ( - getattr(world, f"draw_layer_{layer}_cycle_1", ""), - getattr(world, f"draw_layer_{layer}_cycle_2", ""), - ) + layers = scene.fast64.sm64.draw_layers.layers_by_prop + if layer not in layers: + return default + return layers[layer].preset elif game_mode == "OOT": + if scene.world is None: + return default return ( - getattr(world.ootDefaultRenderModes, f"{layer.lower()}Cycle1", ""), - getattr(world.ootDefaultRenderModes, f"{layer.lower()}Cycle2", ""), + getattr(scene.world.ootDefaultRenderModes, f"{layer.lower()}Cycle1", ""), + getattr(scene.world.ootDefaultRenderModes, f"{layer.lower()}Cycle2", ""), ) else: assert ( @@ -404,7 +388,7 @@ def update_blend_method(material: Material, context): class DrawLayerProperty(PropertyGroup): - sm64: bpy.props.EnumProperty(items=sm64EnumDrawLayers, default="1", update=update_draw_layer) + sm64: bpy.props.EnumProperty(items=get_sm64_draw_layers, update=update_draw_layer) oot: bpy.props.EnumProperty(items=ootEnumDrawLayers, default="Opaque", update=update_draw_layer) def key(self): @@ -4991,7 +4975,6 @@ def mat_register(): World.menu_upper = bpy.props.BoolProperty() World.menu_lower = bpy.props.BoolProperty() World.menu_other = bpy.props.BoolProperty() - World.menu_layers = bpy.props.BoolProperty() Material.is_f3d = bpy.props.BoolProperty() Material.mat_ver = bpy.props.IntProperty(default=1) diff --git a/fast64_internal/operators.py b/fast64_internal/operators.py index fcfba22de..ffd619594 100644 --- a/fast64_internal/operators.py +++ b/fast64_internal/operators.py @@ -22,10 +22,12 @@ class OperatorBase(Operator): icon = "NONE" @classmethod - def draw_props(cls, layout: UILayout, icon="", text: Optional[str] = None, **op_values): + def draw_props(cls, layout: UILayout, icon="", text: Optional[str] = None, enabled=True, **op_values): """Op args are passed to the operator via setattr()""" icon = icon if icon else cls.icon - op = layout.operator(cls.bl_idname, icon=icon, text=text) + col = layout.column() + col.enabled = enabled + op = col.operator(cls.bl_idname, icon=icon, text=text) for key, value in op_values.items(): setattr(op, key, value) return op diff --git a/fast64_internal/repo_settings.py b/fast64_internal/repo_settings.py index 93c2504d9..c2f674c8b 100644 --- a/fast64_internal/repo_settings.py +++ b/fast64_internal/repo_settings.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: from .f3d.f3d_material import RDPSettings -CUR_VERSION = 1.0 +CUR_VERSION = 1.1 class SaveRepoSettings(OperatorBase): diff --git a/fast64_internal/sm64/__init__.py b/fast64_internal/sm64/__init__.py index 81fdbf596..e23d68835 100644 --- a/fast64_internal/sm64/__init__.py +++ b/fast64_internal/sm64/__init__.py @@ -1,3 +1,7 @@ +from bpy.utils import register_class, unregister_class +from bpy.types import PropertyGroup +from bpy.props import PointerProperty + from .settings import ( settings_props_register, settings_props_unregister, diff --git a/fast64_internal/sm64/settings/properties.py b/fast64_internal/sm64/settings/properties.py index 3d69142f8..49ad2fcb9 100644 --- a/fast64_internal/sm64/settings/properties.py +++ b/fast64_internal/sm64/settings/properties.py @@ -19,6 +19,7 @@ from ..sm64_objects import SM64_CombinedObjectProperties from ..sm64_utility import export_rom_ui_warnings, import_rom_ui_warnings from ..tools import SM64_AddrConvProperties +from ..sm64_f3d_writer import SM64_DrawLayersProperties from .constants import ( enum_refresh_versions, @@ -47,6 +48,7 @@ class SM64_Properties(PropertyGroup): export_type: EnumProperty(items=enum_export_type, name="Export Type", default="C") goal: EnumProperty(items=enum_sm64_goal_type, name="Goal", default="All") combined_export: bpy.props.PointerProperty(type=SM64_CombinedObjectProperties) + draw_layers: bpy.props.PointerProperty(type=SM64_DrawLayersProperties) blender_to_sm64_scale: FloatProperty( name="Blender To SM64 Scale", @@ -141,6 +143,7 @@ def upgrade_changed_props(): for scene in bpy.data.scenes: sm64_props: SM64_Properties = scene.fast64.sm64 sm64_props.address_converter.upgrade_changed_props(scene) + sm64_props.draw_layers.upgrade_changed_props(scene) if sm64_props.version == SM64_Properties.cur_version: continue upgrade_old_prop( diff --git a/fast64_internal/sm64/settings/repo_settings.py b/fast64_internal/sm64/settings/repo_settings.py index a32df8621..215f0c3e5 100644 --- a/fast64_internal/sm64/settings/repo_settings.py +++ b/fast64_internal/sm64/settings/repo_settings.py @@ -6,16 +6,8 @@ def save_sm64_repo_settings(scene: Scene): - world = scene.world data: dict[str, Any] = {} - draw_layers: dict[str, Any] = {} - data["draw_layers"] = draw_layers - - for layer in range(8): - draw_layers[layer] = { - "cycle_1": getattr(world, f"draw_layer_{layer}_cycle_1"), - "cycle_2": getattr(world, f"draw_layer_{layer}_cycle_2"), - } + data["draw_layers"] = scene.fast64.sm64.draw_layers.to_dict() sm64_props = scene.fast64.sm64 data.update(sm64_props.to_repo_settings()) @@ -23,15 +15,8 @@ def save_sm64_repo_settings(scene: Scene): def load_sm64_repo_settings(scene: Scene, data: dict[str, Any]): - world = scene.world - - draw_layers = data.get("draw_layers", {}) - for layer in range(8): - draw_layer = draw_layers.get(str(layer), {}) - if "cycle_1" in draw_layer: - set_prop_if_in_data(world, f"draw_layer_{layer}_cycle_1", draw_layer, "cycle_1") - if "cycle_2" in draw_layer: - set_prop_if_in_data(world, f"draw_layer_{layer}_cycle_2", draw_layer, "cycle_2") + if "draw_layers" in data: + scene.fast64.sm64.draw_layers.from_dict(data["draw_layers"]) sm64_props = scene.fast64.sm64 sm64_props.from_repo_settings(data) diff --git a/fast64_internal/sm64/sm64_constants.py b/fast64_internal/sm64/sm64_constants.py index 68b0c4bb9..21aeb018c 100644 --- a/fast64_internal/sm64/sm64_constants.py +++ b/fast64_internal/sm64/sm64_constants.py @@ -3946,3 +3946,46 @@ def get_member_as_dict(name: str, member: DictOrVal[T]): "pipelineMode": "G_PM_1PRIMITIVE", }, } + +DEFAULT_DRAW_LAYER_SETTINGS = { + "Background": { + "enum": "LAYER_FORCE", + "index": 0, + "preset": ["G_RM_ZB_OPA_SURF", "G_RM_ZB_OPA_SURF2"], + }, + "Opaque": { + "enum": "LAYER_OPAQUE", + "index": 1, + "preset": ["G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"], + }, + "Opaque Decal": { + "enum": "LAYER_OPAQUE_DECAL", + "index": 2, + "preset": ["G_RM_AA_ZB_OPA_DECAL", "G_RM_AA_ZB_OPA_DECAL2"], + }, + "Opaque Intersecting": { + "enum": "LAYER_OPAQUE_INTER", + "index": 3, + "preset": ["G_RM_AA_ZB_OPA_INTER", "G_RM_AA_ZB_OPA_INTER2"], + }, + "Cutout": { + "enum": "LAYER_ALPHA", + "index": 4, + "preset": ["G_RM_AA_ZB_TEX_EDGE", "G_RM_AA_ZB_TEX_EDGE2"], + }, + "Transparent": { + "enum": "LAYER_TRANSPARENT", + "index": 5, + "preset": ["G_RM_AA_ZB_XLU_SURF", "G_RM_AA_ZB_XLU_SURF2"], + }, + "Transparent Decal": { + "enum": "LAYER_TRANSPARENT_DECAL", + "index": 6, + "preset": ["G_RM_AA_ZB_XLU_DECAL", "G_RM_AA_ZB_XLU_DECAL2"], + }, + "Transparent Intersecting": { + "enum": "LAYER_TRANSPARENT_INTER", + "index": 7, + "preset": ["G_RM_AA_ZB_XLU_INTER", "G_RM_AA_ZB_XLU_INTER2"], + }, +} diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 1aad38346..8131a89aa 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -4,6 +4,9 @@ from math import ceil, log, radians from mathutils import Matrix, Vector from bpy.utils import register_class, unregister_class +from bpy.types import PropertyGroup, UILayout, Scene +from bpy.props import StringProperty, BoolProperty, CollectionProperty, IntProperty + from ..panels import SM64_Panel from ..f3d.f3d_writer import exportF3DCommon, saveModeSetting from ..f3d.f3d_texture_writer import TexInfo @@ -64,12 +67,16 @@ CData, CScrollData, PluginError, + copyPropertyGroup, + multilineLabel, raisePluginError, prop_split, + draw_and_check_tab, encodeSegmentedAddr, applyRotation, toAlnum, checkIfPathExists, + upgrade_old_prop, overwriteData, getExportDir, writeMaterialFiles, @@ -85,9 +92,11 @@ makeWriteInfoBox, writeBoxExportType, create_or_get_world, + intToHex, ) +from ..operators import OperatorBase -from .sm64_constants import defaultExtendSegment4, bank0Segment, insertableBinaryTypes +from .sm64_constants import DEFAULT_DRAW_LAYER_SETTINGS, defaultExtendSegment4, bank0Segment, insertableBinaryTypes enumHUDExportLocation = [ @@ -105,7 +114,14 @@ class SM64Model(FModel): def __init__(self, name, DLFormat, matWriteMethod): FModel.__init__(self, name, DLFormat, matWriteMethod) - self.no_light_direction = bpy.context.scene.fast64.sm64.matstack_fix + sm64_props = bpy.context.scene.fast64.sm64 + self.no_light_direction = sm64_props.matstack_fix + self.draw_layers = sm64_props.draw_layers + self.draw_layers.populate() + if self.draw_layers.repeated_indices: + raise PluginError( + "World draw layers have repeated indexes: " + {self.draw_layers.repeated_indices_str.replace("\n", " ")} + ) self.layer_adapted_fmats = {} self.draw_overrides: dict[FMesh, dict[tuple, tuple[GfxList, list["DisplayListNode"]]]] = {} @@ -113,10 +129,8 @@ def getDrawLayerV3(self, obj): return int(obj.draw_layer_static) def getRenderMode(self, drawLayer): - world = create_or_get_world(bpy.context.scene) - cycle1 = getattr(world, "draw_layer_" + str(drawLayer) + "_cycle_1") - cycle2 = getattr(world, "draw_layer_" + str(drawLayer) + "_cycle_2") - return (cycle1, cycle2) + assert drawLayer in self.draw_layers.layers_by_index, f"{drawLayer} is not a valid draw layer" + return self.draw_layers.layers_by_index[drawLayer].preset class SM64GfxFormatter(GfxFormatter): @@ -867,25 +881,10 @@ def poll(cls, context): return context.scene.gameEditorMode == "SM64" def draw(self, context): - world = context.scene.world - if not world: - return - - inputGroup = self.layout.column() - inputGroup.prop( - world, "menu_layers", text="Draw Layers", icon="TRIA_DOWN" if world.menu_layers else "TRIA_RIGHT" - ) - if world.menu_layers: - for i in range(8): - drawLayerUI(inputGroup, i, world) - - -def drawLayerUI(layout, drawLayer, world): - box = layout.box() - box.label(text="Layer " + str(drawLayer)) - row = box.row() - row.prop(world, "draw_layer_" + str(drawLayer) + "_cycle_1", text="") - row.prop(world, "draw_layer_" + str(drawLayer) + "_cycle_2", text="") + col = self.layout.column() + draw_layer_props = context.scene.fast64.sm64.draw_layers + if draw_and_check_tab(col, draw_layer_props, "tab"): + draw_layer_props.draw_props(col) class SM64_MaterialPanel(bpy.types.Panel): @@ -915,7 +914,222 @@ def draw(self, context): ui_procAnim(material, col, useDict["Texture 0"], useDict["Texture 1"], "SM64 UV Texture Scroll", False) +class SM64_DrawLayerOps(OperatorBase): + bl_idname = "scene.sm64_draw_layer_ops" + bl_label = "" + bl_description = "Remove or add draw layers to the world" + bl_options = {"UNDO"} + + index: IntProperty() + op_name: StringProperty() + + def execute_operator(self, context): + layer_props: SM64_DrawLayersProperties = context.scene.fast64.sm64.draw_layers + if self.op_name != "DEFAULTS": + layer_props.populate() + if layer_props.lock: + raise PluginError("Draw layer operators are locked by default, unlock them by disabling the lock icon") + layers = layer_props.layers + if self.op_name == "ADD": + layers.add() + added_layer = layers[-1] + base_layer = layers[self.index] + copyPropertyGroup(base_layer, added_layer) + added_layer.name = f"{base_layer.name} (Copy)" + added_layer.enum = f"{base_layer.enum}_COPY" + added_layer.index = layers[self.index].index + 1 + layers.move(len(layers) - 1, self.index + 1) + elif self.op_name == "REMOVE": + layer_props.layers.remove(self.index) + layer_props.update_all_materials(self.index) + elif self.op_name == "DEFAULTS": + layer_props.populate(force_default=True) + else: + raise NotImplementedError(f'Unimplemented internal draw layer op "{self.op_name}"') + + +class SM64_DrawLayerProperties(PropertyGroup): + name: StringProperty(name="Name", default="Custom") + enum: StringProperty(name="Enum", default="LAYER_CUSTOM") + index: IntProperty(name="Index", default=8, update=update_world_default_rendermode) + cycle_1: StringProperty(name="", default="G_RM_AA_ZB_OPA_SURF", update=update_world_default_rendermode) + cycle_2: StringProperty(name="", default="G_RM_AA_ZB_OPA_SURF2", update=update_world_default_rendermode) + + @property + def preset(self): + return [self.cycle_1, self.cycle_2] + + def to_dict(self): + return {"enum": self.enum, "index": self.index, "preset": self.preset} + + def from_dict(self, data: dict): + self.enum = data.get("enum", "LAYER_CUSTOM") + self.index = data.get("index", 8) + self.cycle_1, self.cycle_2 = data.get("preset", ["G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"]) + + def draw_props(self, layout: UILayout): + col = layout.column() + prop_split(col, self, "name", "Name") + + index_split = col.split(factor=0.34) + index_split.prop(self, "index") + index_split.prop(self, "enum") + + f3d = get_F3D_GBI() + rendermode_split = col.split(factor=0.18) + rendermode_split.label(text="Render Mode:") + cycles_row = rendermode_split.row() + for i in range(1, 3): + cycle_layout = cycles_row.column() + if not hasattr(f3d, getattr(self, f"cycle_{i}")): + col.label(text=f"Cycle {i} rendermode is not valid", icon="ERROR") + cycle_layout.alert = True + cycle_layout.prop(self, f"cycle_{i}", text="") + + +class SM64_DrawLayersProperties(PropertyGroup): + internal_defaults_set: BoolProperty() + tab: BoolProperty(name="SM64 Draw Layers") + lock: BoolProperty( + name="", + default=True, + description="(This feature is for advanced users, use at your own risk)\n" + "Disable the lock to remove or add new draw layers.", + ) + layers: CollectionProperty(type=SM64_DrawLayerProperties) + + @property + def repeated_indices(self) -> dict: + indices, repeated_indices = {}, {} + for layer in self.layers: + if layer.index in indices: + repeated_indices[layer.index] = indices[layer.index] + indices[layer.index].append(layer) + else: + indices[layer.index] = [layer] + return repeated_indices + + @property + def repeated_indices_str(self) -> str: + return "\n".join( + f"{index}: [{', '.join([layer.name for layer in layers])}]" + for index, layers in self.repeated_indices.items() + ) + + @property + def layers_by_enum(self): + return {layer.enum: layer for layer in self.layers} + + @property + def layers_by_prop(self): + return {str(layer.index): layer for layer in self.layers} + + @property + def layers_by_index(self): + return {layer.index: layer for layer in self.layers} + + def from_dict(self, data: dict): + self.layers.clear() + for name, layer in data.items(): + self.layers.add() + self.layers[-1].from_dict(layer) + self.layers[-1].name = name + + def to_dict(self): + layers = {} + layer: SM64_DrawLayerProperties + for layer in self.layers: + layers[layer.name] = layer.to_dict() + return layers + + def to_enum(self): + return [ + ( + str(layer.index), + f"{name} ({hex(layer.index)})", + f"{layer.enum} ({layer.index})\n{layer.cycle_1}, {layer.cycle_2}", + layer.index, + ) + for name, layer in self.layers.items() + ] + + def update_all_materials(self, layer_index=-1): + """Update draw layers in materials to ensure any removed draw layer is not being used""" + fallback = list(self.layers_by_prop.values())[0] + for material in bpy.data.materials: + if not material.is_f3d: + continue + material.f3d_mat.draw_layer.sm64 = str(self.layers_by_index.get(layer_index - 1, fallback).index) + + def populate(self, force_default=False): + if self.internal_defaults_set and not force_default: + return + self.from_dict(DEFAULT_DRAW_LAYER_SETTINGS) + self.internal_defaults_set = True + + def upgrade_changed_props(self, scene: Scene): + self.populate() + if scene.world is not None: + for i, layer in self.layers_by_index.items(): + upgrade_old_prop(layer, "cycle_1", scene.world, f"draw_layer_{i}_cycle_1") + upgrade_old_prop(layer, "cycle_2", scene.world, f"draw_layer_{i}_cycle_2") + + def draw_props(self, layout: UILayout): + col = layout.column() + multilineLabel( + col, + "(This feature is for advanced users, use\nat your own risk)\n" + "Disable the lock 🔒 to remove or add new\ndraw layers.", + icon="ERROR", + ) + col.row().prop(self, "lock", icon="LOCKED" if self.lock else "UNLOCKED") + if not self.lock: + col.separator() + multilineLabel( + col, + "These won´t modify your repo's draw\nlayers automatically!\n" + "Tip: Use repo settings and custom presets to\nstreamline your custom draw layer.", + icon="INFO", + ) + layers_col = col.column() + layers_col.enabled = not self.lock + + SM64_DrawLayerOps.draw_props( + layers_col.row(), "MODIFIER_OFF", text="Reset to vanilla SM64 defaults", op_name="DEFAULTS" + ) + + if self.repeated_indices: + col.separator() + error_box = layers_col.box() + error_box.alert = True + multilineLabel(error_box, text=f"Repeated indices:\n{self.repeated_indices_str}", icon="ERROR") + col.separator() + + draw_layer: SM64_DrawLayerProperties + # Enumerate, then sort by index + for i, draw_layer in sorted(enumerate(self.layers), key=lambda layer: layer[1].index): + layer_box = layers_col.box().column() + if draw_layer.index in self.repeated_indices: + bad_layers = self.repeated_indices[draw_layer.index] + bad_layers.remove(draw_layer) + layer_box.alert = True + layer_box.box().label( + text=f"Duplicate index at {', '.join(layer.name for layer in bad_layers)}", icon="ERROR" + ) + row = layer_box.row() + SM64_DrawLayerOps.draw_props(row, "ADD", op_name="ADD", index=i) + SM64_DrawLayerOps.draw_props(row, "REMOVE", enabled=len(self.layers) > 1, op_name="REMOVE", index=i) + draw_layer.draw_props(layer_box) + + +def populate_draw_layers(scene: Scene): # populate draw layers when a new scene is created + scene.fast64.sm64.draw_layers.populate() + + sm64_dl_writer_classes = ( + SM64_DrawLayerOps, + SM64_DrawLayerProperties, + SM64_DrawLayersProperties, SM64_ExportDL, ExportTexRectDraw, UnlinkTexRect, @@ -943,55 +1157,6 @@ def sm64_dl_writer_register(): for cls in sm64_dl_writer_classes: register_class(cls) - bpy.types.World.draw_layer_0_cycle_1 = bpy.props.StringProperty( - default="G_RM_ZB_OPA_SURF", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_0_cycle_2 = bpy.props.StringProperty( - default="G_RM_ZB_OPA_SURF2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_1_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_SURF", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_1_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_SURF2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_2_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_DECAL", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_2_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_DECAL2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_3_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_INTER", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_3_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_OPA_INTER2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_4_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_TEX_EDGE", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_4_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_TEX_EDGE2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_5_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_SURF", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_5_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_SURF2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_6_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_DECAL", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_6_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_DECAL2", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_7_cycle_1 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_INTER", update=update_world_default_rendermode - ) - bpy.types.World.draw_layer_7_cycle_2 = bpy.props.StringProperty( - default="G_RM_AA_ZB_XLU_INTER2", update=update_world_default_rendermode - ) - bpy.types.Scene.DLExportStart = bpy.props.StringProperty(name="Start", default="11D8930") bpy.types.Scene.DLExportEnd = bpy.props.StringProperty(name="End", default="11FFF00") bpy.types.Scene.DLExportGeoPtr = bpy.props.StringProperty(name="Geolayout Pointer", default="132AA8") @@ -1013,6 +1178,8 @@ def sm64_dl_writer_register(): bpy.types.Scene.TexRectCustomExport = bpy.props.BoolProperty(name="Custom Export Path") bpy.types.Scene.TexRectExportType = bpy.props.EnumProperty(name="Export Type", items=enumHUDExportLocation) + bpy.app.handlers.depsgraph_update_post.append(populate_draw_layers) + def sm64_dl_writer_unregister(): for cls in reversed(sm64_dl_writer_classes): @@ -1038,3 +1205,6 @@ def sm64_dl_writer_unregister(): del bpy.types.Scene.texrectImageTexture del bpy.types.Scene.TexRectCustomExport del bpy.types.Scene.TexRectExportType + + if populate_draw_layers in bpy.app.handlers.depsgraph_update_post: + bpy.app.handlers.depsgraph_update_post.remove(populate_draw_layers) diff --git a/fast64_internal/sm64/sm64_geolayout_bone.py b/fast64_internal/sm64/sm64_geolayout_bone.py index 855d16808..542392612 100644 --- a/fast64_internal/sm64/sm64_geolayout_bone.py +++ b/fast64_internal/sm64/sm64_geolayout_bone.py @@ -3,7 +3,7 @@ from bpy.types import Bone, Object, Panel, Operator, Armature, Mesh, Material, PropertyGroup from bpy.utils import register_class, unregister_class from ..utility import PluginError, prop_split, obj_scale_is_unified -from ..f3d.f3d_material import sm64EnumDrawLayers +from ..f3d.f3d_material import get_sm64_draw_layers from .sm64_geolayout_utility import createBoneGroups, addBoneToGroup from bpy.props import ( @@ -286,7 +286,7 @@ class SwitchOptionProperty(PropertyGroup): specificOverrideArray: CollectionProperty(type=MaterialPointerProperty, name="Specified Materials To Override") specificIgnoreArray: CollectionProperty(type=MaterialPointerProperty, name="Specified Materials To Ignore") overrideDrawLayer: BoolProperty() - drawLayer: EnumProperty(items=sm64EnumDrawLayers, name="Draw Layer") + drawLayer: EnumProperty(items=get_sm64_draw_layers, name="Draw Layer") expand: BoolProperty() @@ -520,7 +520,7 @@ def sm64_bone_register(): name="Geolayout Command", items=enumBoneType, default="DisplayListWithOffset", update=updateBone ) - Bone.draw_layer = EnumProperty(name="Draw Layer", items=sm64EnumDrawLayers, default="1") + Bone.draw_layer = EnumProperty(name="Draw Layer", items=get_sm64_draw_layers) # Scale Bone.geo_scale = FloatProperty(name="Scale", min=2 ** (-16), max=2 ** (16), default=1) @@ -554,7 +554,7 @@ def sm64_bone_register(): # Static Geolayout Object.geo_cmd_static = EnumProperty(name="Geolayout Command", items=enumGeoStaticType, default="Optimal") - Object.draw_layer_static = EnumProperty(name="Draw Layer", items=sm64EnumDrawLayers, default="1") + Object.draw_layer_static = EnumProperty(name="Draw Layer", items=get_sm64_draw_layers) Object.use_render_area = BoolProperty(name="Use Render Area") Object.culling_radius = FloatProperty(name="Culling Radius", default=10) diff --git a/fast64_internal/sm64/sm64_geolayout_classes.py b/fast64_internal/sm64/sm64_geolayout_classes.py index 74c0acfdf..ae7379488 100644 --- a/fast64_internal/sm64/sm64_geolayout_classes.py +++ b/fast64_internal/sm64/sm64_geolayout_classes.py @@ -17,6 +17,7 @@ join_c_args, radians_to_s16, geoNodeRotateOrder, + create_or_get_world, ) from ..f3d.f3d_bleed import BleedGraphics from ..f3d.f3d_gbi import FMaterial, FModel, GbiMacro, GfxList @@ -52,30 +53,16 @@ ) from .sm64_utility import convert_addr_to_func -drawLayerNames = { - 0: "LAYER_FORCE", - 1: "LAYER_OPAQUE", - 2: "LAYER_OPAQUE_DECAL", - 3: "LAYER_OPAQUE_INTER", - 4: "LAYER_ALPHA", - 5: "LAYER_TRANSPARENT", - 6: "LAYER_TRANSPARENT_DECAL", - 7: "LAYER_TRANSPARENT_INTER", -} - - -def getDrawLayerName(drawLayer): - layer = drawLayer - if drawLayer is not None: - try: - # Cast draw layer to int so it can be mapped to a name - layer = int(drawLayer) - except ValueError: - pass - if layer in drawLayerNames: - return drawLayerNames[layer] - else: - return str(drawLayer) + +def getDrawLayerName(draw_layer: str): + layer_props = bpy.context.scene.fast64.sm64.draw_layers + if draw_layer in layer_props.layers_by_enum: + return draw_layer + try: + assert draw_layer in layer_props.layers_by_index, f"{draw_layer} is not a valid draw layer" + return layer_props.layers_by_index[draw_layer].enum + except ValueError: + raise PluginError(f"{draw_layer} is not a valid int") def addFuncAddress(command, func):