From 8ef2b020fa268417ae05f4508d52586ccd5b281e Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 15 Sep 2024 16:04:46 +0100 Subject: [PATCH 01/12] [SM64/F3D] Use WriteDifferingAndRevert for bleed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Write all logic remains unaffected, obviously. A new dict was added to map each mode cmd to its default. For the actual bleed part, we fIrst need to add geo mode reverts of the last material to the geo mode of the current material, since the current material may not set them now. For othermodes we do something different, get all reverts and add any that doesn´t get set again by the current material ignoring bleeding. For the geo mode revert, we keep track of one geo mode command for set and clear, updating it as we go. For othermodes we keep track of all of the command types and then revert them using the new dict. --- fast64_internal/f3d/f3d_bleed.py | 125 +++++++++++++++--- fast64_internal/f3d/f3d_gbi.py | 87 ++++++------ fast64_internal/f3d/f3d_writer.py | 5 - fast64_internal/sm64/sm64_f3d_writer.py | 2 +- fast64_internal/sm64/sm64_geolayout_writer.py | 4 +- fast64_internal/sm64/sm64_level_writer.py | 3 +- 6 files changed, 146 insertions(+), 80 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 0e6faaa9b..adb1d6861 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -7,9 +7,24 @@ from ..utility import create_or_get_world from .f3d_gbi import ( + DPPipelineMode, + DPSetAlphaCompare, + DPSetAlphaDither, + DPSetColorDither, + DPSetCombineKey, + DPSetCycleType, + DPSetDepthSource, + DPSetTextureConvert, + DPSetTextureDetail, + DPSetTextureFilter, + DPSetTextureLOD, + DPSetTextureLUT, + DPSetTexturePersp, GfxTag, GfxListTag, + SPGeometryMode, SPMatrix, + SPSetOtherModeSub, SPVertex, SPViewport, SPDisplayList, @@ -94,27 +109,30 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ def build_default_othermodes(self): defaults = create_or_get_world(bpy.context.scene).rdp_defaults - othermode_H = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - self.is_f3d_old, []) + othermode_L: dict[SPSetOtherModeSub:str] = {} + othermode_L[DPSetAlphaCompare] = defaults.g_mdsft_alpha_compare + othermode_L[DPSetDepthSource] = defaults.g_mdsft_zsrcsel + + othermode_H: dict[SPSetOtherModeSub:str] = {} + othermode_H[DPSetColorDither] = defaults.g_mdsft_rgb_dither + othermode_H[DPSetAlphaDither] = defaults.g_mdsft_alpha_dither + othermode_H[DPSetCombineKey] = defaults.g_mdsft_combkey + othermode_H[DPSetTextureConvert] = defaults.g_mdsft_textconv + othermode_H[DPSetTextureFilter] = defaults.g_mdsft_text_filt + othermode_H[DPSetTextureLUT] = defaults.g_mdsft_textlut + othermode_H[DPSetTextureLOD] = defaults.g_mdsft_textlod + othermode_H[DPSetTextureDetail] = defaults.g_mdsft_textdetail + othermode_H[DPSetTexturePersp] = defaults.g_mdsft_textpersp + othermode_H[DPSetCycleType] = defaults.g_mdsft_cycletype + othermode_H[DPPipelineMode] = defaults.g_mdsft_pipeline + self.default_othermode_dict = othermode_L | othermode_H + self.default_othermode_H = SPSetOtherMode( + "G_SETOTHERMODE_H", 4, 20 - self.is_f3d_old, list(othermode_H.values()) + ) # if the render mode is set, it will be consider non-default a priori - othermode_L = SPSetOtherMode("G_SETOTHERMODE_L", 0, 3 - self.is_f3d_old, []) - - othermode_L.flagList.append(defaults.g_mdsft_alpha_compare) - othermode_L.flagList.append(defaults.g_mdsft_zsrcsel) - - othermode_H.flagList.append(defaults.g_mdsft_rgb_dither) - othermode_H.flagList.append(defaults.g_mdsft_alpha_dither) - othermode_H.flagList.append(defaults.g_mdsft_combkey) - othermode_H.flagList.append(defaults.g_mdsft_textconv) - othermode_H.flagList.append(defaults.g_mdsft_text_filt) - othermode_H.flagList.append(defaults.g_mdsft_textlut) - othermode_H.flagList.append(defaults.g_mdsft_textlod) - othermode_H.flagList.append(defaults.g_mdsft_textdetail) - othermode_H.flagList.append(defaults.g_mdsft_textpersp) - othermode_H.flagList.append(defaults.g_mdsft_cycletype) - othermode_H.flagList.append(defaults.g_mdsft_pipeline) - - self.default_othermode_L = othermode_L - self.default_othermode_H = othermode_H + self.default_othermode_L = SPSetOtherMode( + "G_SETOTHERMODE_L", 0, 3 - self.is_f3d_old, list(othermode_L.values()) + ) def bleed_fModel(self, fModel: FModel, fMeshes: dict[FMesh]): # walk fModel, no order to drawing is observed, so last_mat is not kept track of @@ -243,12 +261,32 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): commands_bled = copy.copy(gfx) commands_bled.commands = copy.copy(gfx.commands) # copy the commands also last_cmd_list = last_mat.mat_only_DL.commands + + # handle write diff, save pre bleed cmds + geo_cmd = next((cmd for cmd in commands_bled.commands if type(cmd) == SPGeometryMode), None) + othermode_cmds = [cmd for cmd in commands_bled.commands if isinstance(cmd, SPSetOtherModeSub)] + for j, cmd in enumerate(gfx.commands): if self.bleed_individual_cmd(commands_bled, cmd, bleed_state, last_cmd_list): commands_bled.commands[j] = None # remove Nones from list while None in commands_bled.commands: commands_bled.commands.remove(None) + + # handle write diff + revert_geo_cmd = next((cmd for cmd in last_mat.revert.commands if type(cmd) == SPGeometryMode), None) + geo_cmd_bleeded = geo_cmd is not None and geo_cmd not in commands_bled.commands + # if there was a geo command, and it wasnt bleeded, add revert's modes to it + if not geo_cmd_bleeded and geo_cmd and revert_geo_cmd: + geo_cmd.extend(revert_geo_cmd.clearFlagList, revert_geo_cmd.setFlagList) + # if there was no geo command but there was a revert, add the revert command + elif geo_cmd is None and revert_geo_cmd: + commands_bled.commands.insert(0, revert_geo_cmd) + + for revert_cmd in [cmd for cmd in last_mat.revert.commands if isinstance(cmd, SPSetOtherModeSub)]: + othermode_cmd = next((cmd for cmd in othermode_cmds if type(cmd) == type(revert_cmd)), None) + if othermode_cmd is None: # if there is no equivelent cmd, it must be using the revert + commands_bled.commands.insert(0, revert_cmd) else: commands_bled = self.bleed_cmd_list(cur_fmat.mat_only_DL, bleed_state) # some syncs may become redundant after bleeding @@ -388,6 +426,17 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: elif cmd_type == SPClearGeometryMode and cmd_use != self.default_clear_geo: reset_cmds.append(self.default_clear_geo) + elif cmd_type == SPGeometryMode: # revert cmd includes everything from the start + # First, figure out what needs to be cleared or set + set_list, clear_list = {}, {} + if cmd_use.setFlagList != self.default_set_geo.flagList: + clear_list = set(cmd_use.setFlagList) - set(self.default_set_geo.flagList) + if cmd_use.clearFlagList != self.default_clear_geo.flagList: + set_list = set(cmd_use.clearFlagList) - set(self.default_clear_geo.flagList) + + if set_list or clear_list: + reset_cmds.append(SPGeometryMode(list(clear_list), list(set_list))) + elif cmd_type == "G_SETOTHERMODE_H": if cmd_use != self.default_othermode_H: reset_cmds.append(self.default_othermode_H) @@ -407,6 +456,11 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: elif cmd_type == "G_SETOTHERMODE_L": if cmd_use != self.default_othermode_L: reset_cmds.append(self.default_othermode_L) + + elif isinstance(cmd_use, SPSetOtherModeSub): + default = self.default_othermode_dict[cmd_type] + if cmd_use.mode != default: + reset_cmds.append(cmd_type(default)) return reset_cmds def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, last_cmd_list: GfxList = None): @@ -438,6 +492,11 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in if not last_cmd_list: return self.bleed_self_conflict + if isinstance(cmd, SPSetOtherModeSub): + if bleed_state != self.bleed_start: + return cmd in last_cmd_list + else: + return cmd.mode == self.default_othermode_dict[type(cmd)] # apply specific logic to these cmds, see functions below, otherwise default behavior is to bleed if cmd is in the last list bleed_func = getattr(self, (f"bleed_{type(cmd).__name__}"), None) if bleed_func: @@ -454,6 +513,12 @@ def bleed_SPLoadGeometryMode( else: return cmd == self.default_load_geo + def bleed_SPGeometryMode(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, last_cmd_list: GfxList = None): + if bleed_state != self.bleed_start: + return cmd in last_cmd_list + else: + return cmd.clearFlagList == self.default_clear_geo and cmd.setFlagList == self.default_set_geo + def bleed_SPSetGeometryMode( self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, last_cmd_list: GfxList = None ): @@ -531,6 +596,26 @@ def add_reset_cmd(self, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]): SPClearGeometryMode, DPSetRenderMode, ) + if type(cmd) == SPGeometryMode: + if SPGeometryMode not in reset_cmd_dict: + reset_cmd_dict[SPGeometryMode] = SPGeometryMode([], []) + reset_cmd_dict[SPGeometryMode].extend(cmd.clearFlagList, cmd.setFlagList) + elif isinstance(cmd, SPSetOtherModeSub): + l: SPSetOtherMode = reset_cmd_dict.get("G_SETOTHERMODE_L") + h: SPSetOtherMode = reset_cmd_dict.get("G_SETOTHERMODE_H") + if l or h: # should never be reached, but if we reach it we are prepared + existing_mode = next((mode.startswith(cmd.mode_prefix) for mode in h.flagList + l.flagList), None) + if h and cmd.is_othermodeh: + if existing_mode: + h.flagList.remove(existing_mode) + h.flagList.append(cmd.mode) + if l and not cmd.is_othermodeh: + if existing_mode: + l.flagList.remove(existing_mode) + l.flagList.append(cmd.mode) + else: + reset_cmd_dict[type(cmd)] = cmd + # separate other mode H and othermode L if type(cmd) == SPSetOtherMode: reset_cmd_dict[cmd.cmd] = cmd diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 1eb5b7d80..a1186260b 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4266,6 +4266,12 @@ class SPGeometryMode(GbiMacro): clearFlagList: list setFlagList: list + def extend(self, clear_list: list, set_list: list): + clear_list = set(self.clearFlagList + clear_list) + set_list = set(self.setFlagList + set_list) + self.setFlagList = list(set_list - clear_list) + self.clearFlagList = list(clear_list - set_list) + def to_binary(self, f3d, segments): if f3d.F3DEX_GBI_2: wordClear = geoFlagListToWord(self.clearFlagList, f3d) @@ -4339,10 +4345,27 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPPipelineMode(GbiMacro): - # mode is a string +class SPSetOtherModeSub(GbiMacro): mode: str + is_othermodeh = False + + @property + def mode_prefix(self): + return "_".join(self.mode.split("_")[:2]) + + +@dataclass(unsafe_hash=True) +class SPSetOtherModeLSub(SPSetOtherModeSub): + is_othermodeh = False + + +@dataclass(unsafe_hash=True) +class SPSetOtherModeHSub(SPSetOtherModeSub): + is_othermodeh = True + +@dataclass(unsafe_hash=True) +class DPPipelineMode(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_PM_1PRIMITIVE": modeVal = f3d.G_PM_1PRIMITIVE @@ -4352,10 +4375,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetCycleType(GbiMacro): - # mode is a string - mode: str - +class DPSetCycleType(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_CYC_1CYCLE": modeVal = f3d.G_CYC_1CYCLE @@ -4369,10 +4389,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTexturePersp(GbiMacro): - # mode is a string - mode: str - +class DPSetTexturePersp(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TP_NONE": modeVal = f3d.G_TP_NONE @@ -4382,10 +4399,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTextureDetail(GbiMacro): - # mode is a string - mode: str - +class DPSetTextureDetail(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TD_CLAMP": modeVal = f3d.G_TD_CLAMP @@ -4397,10 +4411,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTextureLOD(GbiMacro): - # mode is a string - mode: str - +class DPSetTextureLOD(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TL_TILE": modeVal = f3d.G_TL_TILE @@ -4410,10 +4421,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTextureLUT(GbiMacro): - # mode is a string - mode: str - +class DPSetTextureLUT(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TT_NONE": modeVal = f3d.G_TT_NONE @@ -4427,10 +4435,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTextureFilter(GbiMacro): - # mode is a string - mode: str - +class DPSetTextureFilter(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TF_POINT": modeVal = f3d.G_TF_POINT @@ -4442,10 +4447,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetTextureConvert(GbiMacro): - # mode is a string - mode: str - +class DPSetTextureConvert(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_TC_CONV": modeVal = f3d.G_TC_CONV @@ -4457,10 +4459,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetCombineKey(GbiMacro): - # mode is a string - mode: str - +class DPSetCombineKey(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_CK_NONE": modeVal = f3d.G_CK_NONE @@ -4470,10 +4469,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetColorDither(GbiMacro): - # mode is a string - mode: str - +class DPSetColorDither(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_CD_MAGICSQ": modeVal = f3d.G_CD_MAGICSQ @@ -4489,10 +4485,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetAlphaDither(GbiMacro): - # mode is a string - mode: str - +class DPSetAlphaDither(SPSetOtherModeHSub): def to_binary(self, f3d, segments): if self.mode == "G_AD_PATTERN": modeVal = f3d.G_AD_PATTERN @@ -4506,10 +4499,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetAlphaCompare(GbiMacro): - # mask is a string - mode: str - +class DPSetAlphaCompare(SPSetOtherModeLSub): def to_binary(self, f3d, segments): if self.mode == "G_AC_NONE": maskVal = f3d.G_AC_NONE @@ -4521,10 +4511,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class DPSetDepthSource(GbiMacro): - # src is a string - src: str - +class DPSetDepthSource(SPSetOtherModeLSub): def to_binary(self, f3d, segments): if self.src == "G_ZS_PIXEL": srcVal = f3d.G_ZS_PIXEL diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index c73a6e50d..bad95d3d4 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1635,11 +1635,6 @@ def saveGeoModeDefinitionF3DEX2(fMaterial, settings, defaults, matWriteMethod): saveGeoModeCommon(saveBitGeoF3DEX2, settings, defaults, (geo, matWriteMethod)) if len(geo.clearFlagList) != 0 or len(geo.setFlagList) != 0: - if len(geo.clearFlagList) == 0: - geo.clearFlagList.append("0") - elif len(geo.setFlagList) == 0: - geo.setFlagList.append("0") - if matWriteMethod == GfxMatWriteMethod.WriteAll: fMaterial.mat_only_DL.commands.append(SPLoadGeometryMode(geo.setFlagList)) else: diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index ab69b095f..4ce300a6b 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -367,7 +367,7 @@ def sm64ExportF3DtoC( fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert if not inline else GfxMatWriteMethod.WriteAll, + GfxMatWriteMethod.WriteDifferingAndRevert, ) fMeshes = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, name, DLFormat, not savePNG) diff --git a/fast64_internal/sm64/sm64_geolayout_writer.py b/fast64_internal/sm64/sm64_geolayout_writer.py index 7a3fb7abd..971a9112e 100644 --- a/fast64_internal/sm64/sm64_geolayout_writer.py +++ b/fast64_internal/sm64/sm64_geolayout_writer.py @@ -393,7 +393,7 @@ def convertArmatureToGeolayout(armatureObj, obj, convertTransformMatrix, camera, fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert if not inline else GfxMatWriteMethod.WriteAll, + GfxMatWriteMethod.WriteDifferingAndRevert, ) if len(armatureObj.children) == 0: @@ -461,7 +461,7 @@ def convertObjectToGeolayout( fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert if not inline else GfxMatWriteMethod.WriteAll, + GfxMatWriteMethod.WriteDifferingAndRevert, ) # convertTransformMatrix = convertTransformMatrix @ \ diff --git a/fast64_internal/sm64/sm64_level_writer.py b/fast64_internal/sm64/sm64_level_writer.py index 1587b43fe..0613db594 100644 --- a/fast64_internal/sm64/sm64_level_writer.py +++ b/fast64_internal/sm64/sm64_level_writer.py @@ -873,11 +873,10 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp level_data = LevelData(camera_data=f"struct CameraTrigger {levelCameraVolumeName}[] = {{\n") - inline = bpy.context.scene.exportInlineF3D fModel = SM64Model( level_name + "_dl", DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert if not inline else GfxMatWriteMethod.WriteAll, + GfxMatWriteMethod.WriteDifferingAndRevert, ) childAreas = [child for child in obj.children if child.type == "EMPTY" and child.sm64_obj_type == "Area Root"] if len(childAreas) == 0: From edf10159b5f6dd4bfe99effc16d764f21cbb87e1 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 15 Sep 2024 19:43:03 +0100 Subject: [PATCH 02/12] remove this --- fast64_internal/f3d/f3d_bleed.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index adb1d6861..4f85dd10d 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -513,12 +513,6 @@ def bleed_SPLoadGeometryMode( else: return cmd == self.default_load_geo - def bleed_SPGeometryMode(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, last_cmd_list: GfxList = None): - if bleed_state != self.bleed_start: - return cmd in last_cmd_list - else: - return cmd.clearFlagList == self.default_clear_geo and cmd.setFlagList == self.default_set_geo - def bleed_SPSetGeometryMode( self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, last_cmd_list: GfxList = None ): From e1033ad91fff9b17b81933103d724475739dcc87 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 15 Sep 2024 22:36:40 +0100 Subject: [PATCH 03/12] scut sabotage --- fast64_internal/f3d/f3d_bleed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 4f85dd10d..f7bba5436 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -421,10 +421,10 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: reset_cmds.append(self.default_load_geo) elif cmd_type == SPSetGeometryMode and cmd_use != self.default_set_geo: - reset_cmds.append(self.default_set_geo) + reset_cmds.append(self.default_clear_geo) elif cmd_type == SPClearGeometryMode and cmd_use != self.default_clear_geo: - reset_cmds.append(self.default_clear_geo) + reset_cmds.append(self.default_set_geo) elif cmd_type == SPGeometryMode: # revert cmd includes everything from the start # First, figure out what needs to be cleared or set From ea77289de7ec22edc624f46a97e4a7a0bc760b46 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 17 Sep 2024 17:10:01 +0100 Subject: [PATCH 04/12] Port over #462 We cannot just assume that othermodeh or othermodel are always setting the same bits, so instead we write the diff of the current cmd to the one already in the reset dict, this means that if a materials sets rendermode and another sets alpha compare (for example) it will still revert the rendermode because those bits will be carried over in the reset dict --- fast64_internal/f3d/f3d_bleed.py | 11 ++++++++--- fast64_internal/f3d/f3d_gbi.py | 11 +++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index f7bba5436..d693dec77 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -60,6 +60,7 @@ GfxList, FTriGroup, GbiMacro, + get_F3D_GBI, ) @@ -73,6 +74,7 @@ class BleedGraphics: def __init__(self): self.bled_gfx_lists = dict() # build world default cmds to compare against, f3d types needed for reset cmd building + self.f3d = get_F3D_GBI() self.is_f3d_old = bpy.context.scene.f3d_type == "F3D" self.is_f3dex2 = "F3DEX2" in bpy.context.scene.f3d_type self.build_default_geo() @@ -336,7 +338,7 @@ def inline_triGroup( tri_cmds = [c for c in tri_list.commands if type(c) == SP1Triangle or type(c) == SP2Triangles] if tri_cmds: reset_cmd_dict[DPPipeSync] = DPPipeSync() - [bleed_gfx_lists.add_reset_cmd(cmd, reset_cmd_dict) for cmd in bleed_gfx_lists.bled_mats] + [bleed_gfx_lists.add_reset_cmd(self.f3d, cmd, reset_cmd_dict) for cmd in bleed_gfx_lists.bled_mats] # pre processes cmd_list and removes cmds deemed useless. subclass and override if this causes a game specific issue def on_bleed_start(self, cmd_list: GfxList): @@ -583,7 +585,7 @@ class BleedGfxLists: bled_mats: GfxList = field(default_factory=list) bled_tex: GfxList = field(default_factory=list) - def add_reset_cmd(self, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]): + def add_reset_cmd(self, f3d: F3D, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]): reset_cmd_list = ( SPLoadGeometryMode, SPSetGeometryMode, @@ -612,7 +614,10 @@ def add_reset_cmd(self, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]): # separate other mode H and othermode L if type(cmd) == SPSetOtherMode: - reset_cmd_dict[cmd.cmd] = cmd + if cmd.cmd in reset_cmd_dict: + reset_cmd_dict[cmd.cmd].add_diff(f3d, cmd) + else: + reset_cmd_dict[cmd.cmd] = copy.deepcopy(cmd) if type(cmd) in reset_cmd_list: reset_cmd_dict[type(cmd)] = cmd diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index a1186260b..6fff2997d 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4335,6 +4335,17 @@ class SPSetOtherMode(GbiMacro): length: int flagList: list + def add_diff(self, f3d, other: SPSetOtherMode): + for flag in self.flagList.copy(): # remove any flag overriden by other + if (getattr(f3d, str(flag), flag) << other.sft) & other.length: + self.flagList.remove(flag) + # add other's flags + self.flagList = list(set(self.flagList + other.flagList)) + + min_max = min(self.sft, other.sft), max(self.sft, other.sft) + max(self.length, other.length) + self.sft = min_max[0] + self.length = min_max[1] - min_max[0] + def to_binary(self, f3d, segments): data = 0 for flag in self.flagList: From a6a789beb62c138aa3fc0878fd62f3d0f275eb51 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 17 Sep 2024 17:24:26 +0100 Subject: [PATCH 05/12] make write different optional, as it can lead to bigger dls --- fast64_internal/sm64/settings/properties.py | 11 +++++++++++ fast64_internal/sm64/settings/repo_settings.py | 2 ++ fast64_internal/sm64/sm64_f3d_writer.py | 8 ++++---- fast64_internal/sm64/sm64_geolayout_writer.py | 4 ++-- fast64_internal/sm64/sm64_level_writer.py | 2 +- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/fast64_internal/sm64/settings/properties.py b/fast64_internal/sm64/settings/properties.py index 471ad617d..39b02b672 100644 --- a/fast64_internal/sm64/settings/properties.py +++ b/fast64_internal/sm64/settings/properties.py @@ -80,11 +80,21 @@ class SM64_Properties(PropertyGroup): name="Matstack Fix", description="Exports account for matstack fix requirements", ) + write_all: BoolProperty( + name="Write All", + description="Write single load geo and set othermode commands instead of writting the difference to defaults. Can result in smaller displaylists but may introduce issues", + ) @property def binary_export(self): return self.export_type in ["Binary", "Insertable Binary"] + @property + def gfx_write_method(self): + from ...f3d.f3d_gbi import GfxMatWriteMethod + + return GfxMatWriteMethod.WriteAll if self.write_all else GfxMatWriteMethod.WriteDifferingAndRevert + @staticmethod def upgrade_changed_props(): old_scene_props_to_new = { @@ -159,6 +169,7 @@ def draw_props(self, layout: UILayout, show_repo_settings: bool = True): prop_split(col, self, "refresh_version", "Refresh (Function Map)") col.prop(self, "force_extended_ram") col.prop(self, "matstack_fix") + col.prop(self, "write_all") col.separator() col.prop(self, "show_importing_menus") diff --git a/fast64_internal/sm64/settings/repo_settings.py b/fast64_internal/sm64/settings/repo_settings.py index f74b7eb3d..3165daac8 100644 --- a/fast64_internal/sm64/settings/repo_settings.py +++ b/fast64_internal/sm64/settings/repo_settings.py @@ -22,6 +22,7 @@ def save_sm64_repo_settings(scene: Scene): data["compression_format"] = sm64_props.compression_format data["force_extended_ram"] = sm64_props.force_extended_ram data["matstack_fix"] = sm64_props.matstack_fix + data["write_all"] = sm64_props.write_all return data @@ -42,6 +43,7 @@ def load_sm64_repo_settings(scene: Scene, data: dict[str, Any]): sm64_props.compression_format = data.get("compression_format", sm64_props.compression_format) sm64_props.force_extended_ram = data.get("force_extended_ram", sm64_props.force_extended_ram) sm64_props.matstack_fix = data.get("matstack_fix", sm64_props.matstack_fix) + sm64_props.write_all = data.get("write_all", sm64_props.write_all) def draw_repo_settings(scene: Scene, layout: UILayout): diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 4ce300a6b..7400695e5 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -367,7 +367,7 @@ def sm64ExportF3DtoC( fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert, + bpy.context.scene.fast64.sm64.gfx_write_method, ) fMeshes = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, name, DLFormat, not savePNG) @@ -488,7 +488,7 @@ def sm64ExportF3DtoC( def exportF3DtoBinary(romfile, exportRange, transformMatrix, obj, segmentData, includeChildren): - fModel = SM64Model(obj.name, DLFormat, GfxMatWriteMethod.WriteDifferingAndRevert) + fModel = SM64Model(obj.name, DLFormat, bpy.context.scene.fast64.sm64.gfx_write_method) fMeshes = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) fMesh = fMeshes[fModel.getDrawLayerV3(obj)] fModel.freePalettes() @@ -508,7 +508,7 @@ def exportF3DtoBinary(romfile, exportRange, transformMatrix, obj, segmentData, i def exportF3DtoBinaryBank0(romfile, exportRange, transformMatrix, obj, RAMAddr, includeChildren): - fModel = SM64Model(obj.name, DLFormat, GfxMatWriteMethod.WriteDifferingAndRevert) + fModel = SM64Model(obj.name, DLFormat, bpy.context.scene.fast64.sm64.gfx_write_method) fMeshes = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) fMesh = fMeshes[fModel.getDrawLayerV3(obj)] segmentData = copy.copy(bank0Segment) @@ -528,7 +528,7 @@ def exportF3DtoBinaryBank0(romfile, exportRange, transformMatrix, obj, RAMAddr, def exportF3DtoInsertableBinary(filepath, transformMatrix, obj, includeChildren): - fModel = SM64Model(obj.name, DLFormat, GfxMatWriteMethod.WriteDifferingAndRevert) + fModel = SM64Model(obj.name, DLFormat, bpy.context.scene.fast64.sm64.gfx_write_method) fMeshes = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) fMesh = fMeshes[fModel.getDrawLayerV3(obj)] diff --git a/fast64_internal/sm64/sm64_geolayout_writer.py b/fast64_internal/sm64/sm64_geolayout_writer.py index 971a9112e..e2702b84b 100644 --- a/fast64_internal/sm64/sm64_geolayout_writer.py +++ b/fast64_internal/sm64/sm64_geolayout_writer.py @@ -393,7 +393,7 @@ def convertArmatureToGeolayout(armatureObj, obj, convertTransformMatrix, camera, fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert, + bpy.context.scene.fast64.sm64.gfx_write_method, ) if len(armatureObj.children) == 0: @@ -461,7 +461,7 @@ def convertObjectToGeolayout( fModel = SM64Model( name, DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert, + bpy.context.scene.fast64.sm64.gfx_write_method, ) # convertTransformMatrix = convertTransformMatrix @ \ diff --git a/fast64_internal/sm64/sm64_level_writer.py b/fast64_internal/sm64/sm64_level_writer.py index 0613db594..eba281feb 100644 --- a/fast64_internal/sm64/sm64_level_writer.py +++ b/fast64_internal/sm64/sm64_level_writer.py @@ -876,7 +876,7 @@ def exportLevelC(obj, transformMatrix, level_name, exportDir, savePNG, customExp fModel = SM64Model( level_name + "_dl", DLFormat, - GfxMatWriteMethod.WriteDifferingAndRevert, + bpy.context.scene.fast64.sm64.gfx_write_method, ) childAreas = [child for child in obj.children if child.type == "EMPTY" and child.sm64_obj_type == "Area Root"] if len(childAreas) == 0: From 531548b2786f5d31076d3748090dc8ae29a95d87 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 17 Sep 2024 17:32:41 +0100 Subject: [PATCH 06/12] clean up sm64 repo settings --- fast64_internal/sm64/settings/panels.py | 10 ++++++---- fast64_internal/sm64/settings/properties.py | 20 +++++++++++-------- .../sm64/settings/repo_settings.py | 14 ------------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/fast64_internal/sm64/settings/panels.py b/fast64_internal/sm64/settings/panels.py index 97fe73040..98bf625ef 100644 --- a/fast64_internal/sm64/settings/panels.py +++ b/fast64_internal/sm64/settings/panels.py @@ -1,9 +1,9 @@ from bpy.utils import register_class, unregister_class from bpy.types import Context -from ...panels import SM64_Panel +from ...utility import draw_and_check_tab -from .repo_settings import draw_repo_settings +from ...panels import SM64_Panel class SM64_GeneralSettingsPanel(SM64_Panel): @@ -18,8 +18,10 @@ def draw(self, context: Context): if sm64_props.export_type == "C": # If the repo settings tab is open, we pass show_repo_settings as False # because we want to draw those specfic properties in the repo settings box - draw_repo_settings(scene, col.box()) - col.separator() + box = col.box().column() + if draw_and_check_tab(box, sm64_props, "sm64_repo_settings_tab", icon="PROPERTIES"): + sm64_props.draw_repo_settings(box) + col.separator() sm64_props.draw_props(col, not sm64_props.sm64_repo_settings_tab) else: diff --git a/fast64_internal/sm64/settings/properties.py b/fast64_internal/sm64/settings/properties.py index 39b02b672..1fa5122df 100644 --- a/fast64_internal/sm64/settings/properties.py +++ b/fast64_internal/sm64/settings/properties.py @@ -143,6 +143,16 @@ def upgrade_changed_props(): upgrade_old_prop(combined_props, new, scene, old) sm64_props.version = SM64_Properties.cur_version + def draw_repo_settings(self, layout: UILayout): + col = layout.column() + if not self.binary_export: + col.prop(self, "disable_scroll") + prop_split(col, self, "compression_format", "Compression Format") + prop_split(col, self, "refresh_version", "Refresh (Function Map)") + col.prop(self, "force_extended_ram") + col.prop(self, "matstack_fix") + col.prop(self, "write_all") + def draw_props(self, layout: UILayout, show_repo_settings: bool = True): col = layout.column() @@ -162,14 +172,8 @@ def draw_props(self, layout: UILayout, show_repo_settings: bool = True): directory_ui_warnings(col, abspath(self.decomp_path)) col.separator() - if not self.binary_export: - col.prop(self, "disable_scroll") - if show_repo_settings: - prop_split(col, self, "compression_format", "Compression Format") - prop_split(col, self, "refresh_version", "Refresh (Function Map)") - col.prop(self, "force_extended_ram") - col.prop(self, "matstack_fix") - col.prop(self, "write_all") + if show_repo_settings: + self.draw_repo_settings(col) col.separator() col.prop(self, "show_importing_menus") diff --git a/fast64_internal/sm64/settings/repo_settings.py b/fast64_internal/sm64/settings/repo_settings.py index 3165daac8..1129e0f50 100644 --- a/fast64_internal/sm64/settings/repo_settings.py +++ b/fast64_internal/sm64/settings/repo_settings.py @@ -44,17 +44,3 @@ def load_sm64_repo_settings(scene: Scene, data: dict[str, Any]): sm64_props.force_extended_ram = data.get("force_extended_ram", sm64_props.force_extended_ram) sm64_props.matstack_fix = data.get("matstack_fix", sm64_props.matstack_fix) sm64_props.write_all = data.get("write_all", sm64_props.write_all) - - -def draw_repo_settings(scene: Scene, layout: UILayout): - col = layout.column() - sm64_props = scene.fast64.sm64 - if not draw_and_check_tab(col, sm64_props, "sm64_repo_settings_tab", icon="PROPERTIES"): - return - - prop_split(col, sm64_props, "compression_format", "Compression Format") - prop_split(col, sm64_props, "refresh_version", "Refresh (Function Map)") - col.prop(sm64_props, "force_extended_ram") - col.prop(sm64_props, "matstack_fix") - - col.label(text="See Fast64 repo settings for general settings", icon="INFO") From 1d2623217d221dc40ad0a6f61745fc0007e31ad5 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 18 Sep 2024 10:11:45 +0100 Subject: [PATCH 07/12] im gonna have to rework a bunch of othermode stuff i actually dispise fast64 so much --- fast64_internal/f3d/f3d_bleed.py | 19 +++++++++++-------- fast64_internal/f3d/f3d_gbi.py | 12 ++++++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index d693dec77..c3176d41a 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -276,7 +276,11 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): commands_bled.commands.remove(None) # handle write diff - revert_geo_cmd = next((cmd for cmd in last_mat.revert.commands if type(cmd) == SPGeometryMode), None) + if last_mat.revert: + revert_geo_cmd = next((cmd for cmd in last_mat.revert.commands if type(cmd) == SPGeometryMode), None) + revert_othermode_cmd = [cmd for cmd in last_mat.revert.commands if isinstance(cmd, SPSetOtherModeSub)] + else: + revert_geo_cmd, revert_othermode_cmd = None, [] geo_cmd_bleeded = geo_cmd is not None and geo_cmd not in commands_bled.commands # if there was a geo command, and it wasnt bleeded, add revert's modes to it if not geo_cmd_bleeded and geo_cmd and revert_geo_cmd: @@ -285,7 +289,7 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): elif geo_cmd is None and revert_geo_cmd: commands_bled.commands.insert(0, revert_geo_cmd) - for revert_cmd in [cmd for cmd in last_mat.revert.commands if isinstance(cmd, SPSetOtherModeSub)]: + for revert_cmd in revert_othermode_cmd: othermode_cmd = next((cmd for cmd in othermode_cmds if type(cmd) == type(revert_cmd)), None) if othermode_cmd is None: # if there is no equivelent cmd, it must be using the revert commands_bled.commands.insert(0, revert_cmd) @@ -600,26 +604,25 @@ def add_reset_cmd(self, f3d: F3D, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]) l: SPSetOtherMode = reset_cmd_dict.get("G_SETOTHERMODE_L") h: SPSetOtherMode = reset_cmd_dict.get("G_SETOTHERMODE_H") if l or h: # should never be reached, but if we reach it we are prepared - existing_mode = next((mode.startswith(cmd.mode_prefix) for mode in h.flagList + l.flagList), None) if h and cmd.is_othermodeh: - if existing_mode: + for existing_mode in [mode for mode in h.flagList if mode.startswith(cmd.mode_prefix)]: h.flagList.remove(existing_mode) h.flagList.append(cmd.mode) if l and not cmd.is_othermodeh: - if existing_mode: + for existing_mode in [mode for mode in l.flagList if mode.startswith(cmd.mode_prefix)]: l.flagList.remove(existing_mode) l.flagList.append(cmd.mode) else: reset_cmd_dict[type(cmd)] = cmd # separate other mode H and othermode L - if type(cmd) == SPSetOtherMode: + elif type(cmd) == SPSetOtherMode: if cmd.cmd in reset_cmd_dict: - reset_cmd_dict[cmd.cmd].add_diff(f3d, cmd) + reset_cmd_dict[cmd.cmd].add_other(f3d, cmd) else: reset_cmd_dict[cmd.cmd] = copy.deepcopy(cmd) - if type(cmd) in reset_cmd_list: + elif type(cmd) in reset_cmd_list: reset_cmd_dict[type(cmd)] = cmd diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 6fff2997d..0823cf289 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4335,12 +4335,16 @@ class SPSetOtherMode(GbiMacro): length: int flagList: list - def add_diff(self, f3d, other: SPSetOtherMode): + def extend(self, flags: Iterable | str): + flags = {flags} if isinstance(flags, str) else set(flags) + self.flagList = list(set(self.flagList) | flags) + + def add_other(self, f3d, other: SPSetOtherMode): for flag in self.flagList.copy(): # remove any flag overriden by other if (getattr(f3d, str(flag), flag) << other.sft) & other.length: self.flagList.remove(flag) # add other's flags - self.flagList = list(set(self.flagList + other.flagList)) + self.extend(other.flagList) min_max = min(self.sft, other.sft), max(self.sft, other.sft) + max(self.length, other.length) self.sft = min_max[0] @@ -4524,9 +4528,9 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) class DPSetDepthSource(SPSetOtherModeLSub): def to_binary(self, f3d, segments): - if self.src == "G_ZS_PIXEL": + if self.mode == "G_ZS_PIXEL": srcVal = f3d.G_ZS_PIXEL - elif self.src == "G_ZS_PRIM": + elif self.mode == "G_ZS_PRIM": srcVal = f3d.G_ZS_PRIM return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_ZSRCSEL, 1, srcVal, f3d) From 34f315a507ba1e44ceb89ac660f326f14fdcfcd6 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 18 Sep 2024 10:45:31 +0100 Subject: [PATCH 08/12] RendermodeBlender class --- fast64_internal/f3d/f3d_bleed.py | 6 ++- fast64_internal/f3d/f3d_gbi.py | 72 ++++++++++++------------------- fast64_internal/f3d/f3d_writer.py | 9 +--- 3 files changed, 35 insertions(+), 52 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index c3176d41a..7cb99bb64 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -448,7 +448,11 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: reset_cmds.append(self.default_othermode_H) # render mode takes up most bits of the lower half, so seeing high bit usage is enough to determine render mode was used - elif cmd_type == DPSetRenderMode or (cmd_type == "G_SETOTHERMODE_L" and cmd_use.length >= 31): + elif cmd_type == DPSetRenderMode: + if default_render_mode: + reset_cmds.append(DPSetRenderMode(default_render_mode)) + + elif cmd_type == "G_SETOTHERMODE_L" and cmd_use.length >= 31: if default_render_mode: reset_cmds.append( SPSetOtherMode( diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 0823cf289..2be5ca578 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3389,7 +3389,7 @@ def getattr_virtual(self, field, static): else: return field.name if hasattr(field, "__iter__") and type(field) is not str: - return " | ".join(field) if len(field) else "0" + return " | ".join(map(str, field)) if len(field) else "0" if self._hex > 0 and isinstance(field, int): temp = field if field >= 0 else (1 << (self._hex * 4)) + field return f"{temp:#0{self._hex + 2}x}" # + 2 for the 0x part @@ -4328,6 +4328,23 @@ def gsSPSetOtherMode(cmd, sft, length, data, f3d): return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") +@dataclass(unsafe_hash=True) +class RendermodeBlender: + cycle1: tuple + cycle2: tuple + + def __str__(self) -> str: + return f"GBL_c1({', '.join(self.cycle1)}) | GBL_c2({', '.join(self.cycle1)})" + + def to_c(self, _static=True): + return str(self) + + def to_binary(self, f3d): + return GBL_c1(*[getattr(f3d, str(x), x) for x in self.cycle1]) | GBL_c2( + *[getattr(f3d, str(x), x) for x in self.cycle2] + ) + + @dataclass(unsafe_hash=True) class SPSetOtherMode(GbiMacro): cmd: str @@ -4341,7 +4358,11 @@ def extend(self, flags: Iterable | str): def add_other(self, f3d, other: SPSetOtherMode): for flag in self.flagList.copy(): # remove any flag overriden by other - if (getattr(f3d, str(flag), flag) << other.sft) & other.length: + if isinstance(flag, RendermodeBlender): + value = flag.to_binary(f3d) + else: + value = getattr(f3d, str(flag), flag) + if (value >> other.sft) & other.length: self.flagList.remove(flag) # add other's flags self.extend(other.flagList) @@ -4554,36 +4575,17 @@ def GBL_c2(m1a, m1b, m2a, m2b): @dataclass(unsafe_hash=True) class DPSetRenderMode(GbiMacro): # bl0-3 are string for each blender enum - def __init__(self, flagList, blendList): + def __init__(self, flagList, blender: Optional[RendermodeBlender] = None): self.flagList = flagList - self.use_preset = blendList is None - if not self.use_preset: - self.bl00 = blendList[0] - self.bl01 = blendList[1] - self.bl02 = blendList[2] - self.bl03 = blendList[3] - self.bl10 = blendList[4] - self.bl11 = blendList[5] - self.bl12 = blendList[6] - self.bl13 = blendList[7] - - def getGBL_c(self, f3d): - bl00 = getattr(f3d, self.bl00) - bl01 = getattr(f3d, self.bl01) - bl02 = getattr(f3d, self.bl02) - bl03 = getattr(f3d, self.bl03) - bl10 = getattr(f3d, self.bl10) - bl11 = getattr(f3d, self.bl11) - bl12 = getattr(f3d, self.bl12) - bl13 = getattr(f3d, self.bl13) - return GBL_c1(bl00, bl01, bl02, bl03) | GBL_c2(bl10, bl11, bl12, bl13) + self.use_preset = blender is None + self.blender = blender def to_binary(self, f3d, segments): flagWord = renderFlagListToWord(self.flagList, f3d) if not self.use_preset: return gsSPSetOtherMode( - f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_RENDERMODE, 29, flagWord | self.getGBL_c(f3d), f3d + f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_RENDERMODE, 29, flagWord | self.blender.to_binary(f3d), f3d ) else: return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_RENDERMODE, 29, flagWord, f3d) @@ -4592,25 +4594,7 @@ def to_c(self, static=True): data = "gsDPSetRenderMode(" if static else "gDPSetRenderMode(glistp++, " if not self.use_preset: - data += ( - "GBL_c1(" - + self.bl00 - + ", " - + self.bl01 - + ", " - + self.bl02 - + ", " - + self.bl03 - + ") | GBL_c2(" - + self.bl10 - + ", " - + self.bl11 - + ", " - + self.bl12 - + ", " - + self.bl13 - + "), " - ) + data += self.blender.to_c(static) + ", " for name in self.flagList: data += name + " | " return data[:-3] + ")" diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index bad95d3d4..0a6aed132 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1723,12 +1723,7 @@ def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaults, f3d): flagList, blendList = getRenderModeFlagList(settings, fMaterial) cmd.flagList.extend(flagList) if blendList is not None: - cmd.flagList.extend( - [ - "GBL_c1(" + blendList[0] + ", " + blendList[1] + ", " + blendList[2] + ", " + blendList[3] + ")", - "GBL_c2(" + blendList[4] + ", " + blendList[5] + ", " + blendList[6] + ", " + blendList[7] + ")", - ] - ) + cmd.flagList.append(RendermodeBlender(tuple(blendList[:4]), tuple(blendList[4:]))) fMaterial.mat_only_DL.commands.append(cmd) @@ -1747,7 +1742,7 @@ def saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRen if settings.set_rendermode: flagList, blendList = getRenderModeFlagList(settings, fMaterial) - renderModeSet = DPSetRenderMode(flagList, blendList) + renderModeSet = DPSetRenderMode(flagList, RendermodeBlender(tuple(blendList[:4]), tuple(blendList[4:]))) fMaterial.mat_only_DL.commands.append(renderModeSet) if defaultRenderMode is not None: From a6715210cc37931ae16e913cfe605ba75186e433 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 18 Sep 2024 10:46:28 +0100 Subject: [PATCH 09/12] Update f3d_bleed.py --- fast64_internal/f3d/f3d_bleed.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 7cb99bb64..7a184d7b1 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -447,11 +447,11 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: if cmd_use != self.default_othermode_H: reset_cmds.append(self.default_othermode_H) - # render mode takes up most bits of the lower half, so seeing high bit usage is enough to determine render mode was used elif cmd_type == DPSetRenderMode: if default_render_mode: reset_cmds.append(DPSetRenderMode(default_render_mode)) + # render mode takes up most bits of the lower half, so seeing high bit usage is enough to determine render mode was used elif cmd_type == "G_SETOTHERMODE_L" and cmd_use.length >= 31: if default_render_mode: reset_cmds.append( From 990afcc04ad0cdd85e9abc1874c5e077e2ca6d3e Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 18 Sep 2024 12:05:26 +0100 Subject: [PATCH 10/12] i just want to be done with this --- fast64_internal/f3d/f3d_bleed.py | 41 ++++++++++++++++++------------- fast64_internal/f3d/f3d_gbi.py | 8 ++++-- fast64_internal/f3d/f3d_writer.py | 13 +++++++--- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 7a184d7b1..d1900010f 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -265,8 +265,12 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): last_cmd_list = last_mat.mat_only_DL.commands # handle write diff, save pre bleed cmds + is_rendermode_cmd = lambda cmd: isinstance(cmd, DPSetRenderMode) or ( + isinstance(cmd, SPSetOtherMode) and cmd.sets_rendermode + ) geo_cmd = next((cmd for cmd in commands_bled.commands if type(cmd) == SPGeometryMode), None) othermode_cmds = [cmd for cmd in commands_bled.commands if isinstance(cmd, SPSetOtherModeSub)] + rendermode_cmds = [cmd for cmd in commands_bled.commands if is_rendermode_cmd(cmd)] for j, cmd in enumerate(gfx.commands): if self.bleed_individual_cmd(commands_bled, cmd, bleed_state, last_cmd_list): @@ -279,20 +283,25 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): if last_mat.revert: revert_geo_cmd = next((cmd for cmd in last_mat.revert.commands if type(cmd) == SPGeometryMode), None) revert_othermode_cmd = [cmd for cmd in last_mat.revert.commands if isinstance(cmd, SPSetOtherModeSub)] + revert_rendermode_cmds = [cmd for cmd in last_mat.revert.commands if is_rendermode_cmd(cmd)] else: - revert_geo_cmd, revert_othermode_cmd = None, [] - geo_cmd_bleeded = geo_cmd is not None and geo_cmd not in commands_bled.commands - # if there was a geo command, and it wasnt bleeded, add revert's modes to it - if not geo_cmd_bleeded and geo_cmd and revert_geo_cmd: + revert_geo_cmd, revert_othermode_cmd, revert_rendermode_cmds = None, [], [] + if geo_cmd in commands_bled.commands and revert_geo_cmd: + # if there's a geo command, add revert's modes to it geo_cmd.extend(revert_geo_cmd.clearFlagList, revert_geo_cmd.setFlagList) - # if there was no geo command but there was a revert, add the revert command elif geo_cmd is None and revert_geo_cmd: + # if there was no geo command but there was a revert, add the revert command commands_bled.commands.insert(0, revert_geo_cmd) + # if there is no equivelent cmd, it must be using the revert for revert_cmd in revert_othermode_cmd: othermode_cmd = next((cmd for cmd in othermode_cmds if type(cmd) == type(revert_cmd)), None) if othermode_cmd is None: # if there is no equivelent cmd, it must be using the revert commands_bled.commands.insert(0, revert_cmd) + for revert_cmd in revert_rendermode_cmds: + rendermode_cmd = next((cmd for cmd in rendermode_cmds if cmd == revert_cmd), None) + if rendermode_cmd is None: # if there is no equivelent cmd, it must be using the revert + commands_bled.commands.insert(0, revert_cmd) else: commands_bled = self.bleed_cmd_list(cur_fmat.mat_only_DL, bleed_state) # some syncs may become redundant after bleeding @@ -448,20 +457,18 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: reset_cmds.append(self.default_othermode_H) elif cmd_type == DPSetRenderMode: - if default_render_mode: + if default_render_mode and cmd_use.flagList != default_render_mode: reset_cmds.append(DPSetRenderMode(default_render_mode)) - # render mode takes up most bits of the lower half, so seeing high bit usage is enough to determine render mode was used - elif cmd_type == "G_SETOTHERMODE_L" and cmd_use.length >= 31: - if default_render_mode: - reset_cmds.append( - SPSetOtherMode( - "G_SETOTHERMODE_L", - 0, - 32 - self.is_f3d_old, - [*self.default_othermode_L.flagList, *default_render_mode], - ) - ) + elif cmd_type == "G_SETOTHERMODE_L" and cmd_use.sets_rendermode: + default_othermode_l = SPSetOtherMode( + "G_SETOTHERMODE_L", + 0, + 32 - self.is_f3d_old, + [*self.default_othermode_L.flagList, *default_render_mode], + ) + if default_render_mode and cmd_use.flagList != default_othermode_l.flagList: + reset_cmds.append(default_othermode_l) elif cmd_type == "G_SETOTHERMODE_L": if cmd_use != self.default_othermode_L: diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 2be5ca578..88f0d63a3 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4352,6 +4352,10 @@ class SPSetOtherMode(GbiMacro): length: int flagList: list + @property + def sets_rendermode(self): + return self.cmd == "G_SETOTHERMODE_L" and (self.sft + self.length) > 3 + def extend(self, flags: Iterable | str): flags = {flags} if isinstance(flags, str) else set(flags) self.flagList = list(set(self.flagList) | flags) @@ -4362,12 +4366,12 @@ def add_other(self, f3d, other: SPSetOtherMode): value = flag.to_binary(f3d) else: value = getattr(f3d, str(flag), flag) - if (value >> other.sft) & other.length: + if not value or value >> other.sft > other.length: self.flagList.remove(flag) # add other's flags self.extend(other.flagList) - min_max = min(self.sft, other.sft), max(self.sft, other.sft) + max(self.length, other.length) + min_max = min(self.sft, other.sft), max(self.sft + self.length, other.sft + other.length) self.sft = min_max[0] self.length = min_max[1] - min_max[0] diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 0a6aed132..7f3afa834 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1706,14 +1706,14 @@ def saveOtherModeHDefinitionIndividual(fMaterial, settings, tlut, defaults): def saveOtherModeLDefinition(fMaterial, settings, defaults, defaultRenderMode, matWriteMethod, f3d): if matWriteMethod == GfxMatWriteMethod.WriteAll: - saveOtherModeLDefinitionAll(fMaterial, settings, defaults, f3d) + saveOtherModeLDefinitionAll(fMaterial, settings, defaultRenderMode, f3d) elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRenderMode) else: raise PluginError("Unhandled material write method: " + str(matWriteMethod)) -def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaults, f3d): +def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaultRenderMode, f3d): baseLength = 3 if not settings.set_rendermode else 32 cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, baseLength - f3d.F3D_OLD_GBI, []) cmd.flagList.append(settings.g_mdsft_alpha_compare) @@ -1724,6 +1724,10 @@ def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaults, f3d): cmd.flagList.extend(flagList) if blendList is not None: cmd.flagList.append(RendermodeBlender(tuple(blendList[:4]), tuple(blendList[4:]))) + if defaultRenderMode is not None: # even in write all, we need to revert the rendermode + fMaterial.revert.commands.append( + SPSetOtherMode("G_SETOTHERMODE_L", f3d.G_MDSFT_RENDERMODE, 29 - f3d.F3D_OLD_GBI, defaultRenderMode) + ) fMaterial.mat_only_DL.commands.append(cmd) @@ -1742,7 +1746,10 @@ def saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRen if settings.set_rendermode: flagList, blendList = getRenderModeFlagList(settings, fMaterial) - renderModeSet = DPSetRenderMode(flagList, RendermodeBlender(tuple(blendList[:4]), tuple(blendList[4:]))) + blender = None + if blendList: + blender = RendermodeBlender(tuple(blendList[:4]), tuple(blendList[4:])) + renderModeSet = DPSetRenderMode(flagList, blender) fMaterial.mat_only_DL.commands.append(renderModeSet) if defaultRenderMode is not None: From 7c9209d4884729afec817213ad3cd32b338da4f7 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 1 Oct 2024 08:49:03 +0100 Subject: [PATCH 11/12] [Repo Settings] Only set if different Fixes lag at start up from draw layers being set unnecessarily. Some clean up that I already did in #461 --- __init__.py | 15 +++++++++++++- fast64_internal/repo_settings.py | 19 +++++++----------- fast64_internal/sm64/settings/panels.py | 5 ++--- fast64_internal/sm64/settings/properties.py | 20 +++++++++++++++++-- .../sm64/settings/repo_settings.py | 19 +++++------------- fast64_internal/utility.py | 9 +++++++++ 6 files changed, 55 insertions(+), 32 deletions(-) diff --git a/__init__.py b/__init__.py index d3e5c548c..5ab654ba6 100644 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,7 @@ from . import addon_updater_ops -from .fast64_internal.utility import prop_split, multilineLabel, draw_and_check_tab +from .fast64_internal.utility import prop_split, multilineLabel, prop_group_to_json, set_prop_if_in_data from .fast64_internal.repo_settings import ( draw_repo_settings, @@ -213,6 +213,19 @@ class Fast64Settings_Properties(bpy.types.PropertyGroup): internal_game_update_ver: bpy.props.IntProperty(default=0) + def to_repo_settings(self): + data = {} + data["autoLoad"] = self.auto_repo_load_settings + data["autoPickTextureFormat"] = self.auto_pick_texture_format + if self.auto_pick_texture_format: + data["preferRGBAOverCI"] = self.prefer_rgba_over_ci + return data + + def from_repo_settings(self, data: dict): + set_prop_if_in_data(self, "auto_repo_load_settings", data, "autoLoad") + set_prop_if_in_data(self, "auto_pick_texture_format", data, "autoPickTextureFormat") + set_prop_if_in_data(self, "prefer_rgba_over_ci", data, "preferRGBAOverCI") + class Fast64_Properties(bpy.types.PropertyGroup): """ diff --git a/fast64_internal/repo_settings.py b/fast64_internal/repo_settings.py index 04418e821..e0af49b6f 100644 --- a/fast64_internal/repo_settings.py +++ b/fast64_internal/repo_settings.py @@ -6,7 +6,7 @@ from bpy.props import StringProperty from bpy.path import abspath -from .utility import filepath_checks, prop_split, filepath_ui_warnings, draw_and_check_tab +from .utility import filepath_checks, prop_split, filepath_ui_warnings, draw_and_check_tab, set_prop_if_in_data from .operators import OperatorBase from .f3d.f3d_material import draw_rdp_world_defaults from .sm64.settings.repo_settings import load_sm64_repo_settings, save_sm64_repo_settings @@ -71,13 +71,10 @@ def load_repo_settings(scene: Scene, path: os.PathLike, skip_if_no_auto_load=Fal ) fast64_settings = scene.fast64.settings - fast64_settings.auto_repo_load_settings = data.get("autoLoad", fast64_settings.auto_repo_load_settings) - fast64_settings.auto_pick_texture_format = data.get( - "autoPickTextureFormat", fast64_settings.auto_pick_texture_format - ) - fast64_settings.prefer_rgba_over_ci = data.get("preferRGBAOverCI", fast64_settings.prefer_rgba_over_ci) - scene.f3d_type = data.get("microcode", scene.f3d_type) - scene.saveTextures = data.get("saveTextures", scene.saveTextures) + fast64_settings.from_repo_settings(data) + set_prop_if_in_data(scene, "f3d_type", data, "microcode") + set_prop_if_in_data(scene, "saveTextures", data, "saveTextures") + rdp_defaults: RDPSettings = scene.world.rdp_defaults rdp_defaults.from_dict(data.get("rdpDefaults", {})) @@ -90,12 +87,10 @@ def save_repo_settings(scene: Scene, path: os.PathLike): data = {} data["version"] = CUR_VERSION - data["autoLoad"] = fast64_settings.auto_repo_load_settings + data.update(fast64_settings.to_repo_settings()) data["microcode"] = scene.f3d_type data["saveTextures"] = scene.saveTextures - data["autoPickTextureFormat"] = fast64_settings.auto_pick_texture_format - if fast64_settings.auto_pick_texture_format: - data["preferRGBAOverCI"] = fast64_settings.prefer_rgba_over_ci + rdp_defaults: RDPSettings = scene.world.rdp_defaults data["rdpDefaults"] = rdp_defaults.to_dict() diff --git a/fast64_internal/sm64/settings/panels.py b/fast64_internal/sm64/settings/panels.py index 98bf625ef..ba82351a7 100644 --- a/fast64_internal/sm64/settings/panels.py +++ b/fast64_internal/sm64/settings/panels.py @@ -1,9 +1,8 @@ from bpy.utils import register_class, unregister_class from bpy.types import Context -from ...utility import draw_and_check_tab - from ...panels import SM64_Panel +from ...utility import draw_and_check_tab class SM64_GeneralSettingsPanel(SM64_Panel): @@ -23,7 +22,7 @@ def draw(self, context: Context): sm64_props.draw_repo_settings(box) col.separator() - sm64_props.draw_props(col, not sm64_props.sm64_repo_settings_tab) + sm64_props.draw_props(col, not sm64_props.sm64_repo_settings_tab or sm64_props.binary_export) else: sm64_props.draw_props(col, True) diff --git a/fast64_internal/sm64/settings/properties.py b/fast64_internal/sm64/settings/properties.py index 1fa5122df..ddddb6532 100644 --- a/fast64_internal/sm64/settings/properties.py +++ b/fast64_internal/sm64/settings/properties.py @@ -6,7 +6,7 @@ from bpy.utils import register_class, unregister_class from ...render_settings import on_update_render_settings -from ...utility import directory_path_checks, directory_ui_warnings, prop_split, upgrade_old_prop +from ...utility import directory_path_checks, directory_ui_warnings, prop_split, set_prop_if_in_data, upgrade_old_prop from ..sm64_constants import defaultExtendSegment4 from ..sm64_objects import SM64_CombinedObjectProperties from ..sm64_utility import export_rom_ui_warnings, import_rom_ui_warnings @@ -143,6 +143,22 @@ def upgrade_changed_props(): upgrade_old_prop(combined_props, new, scene, old) sm64_props.version = SM64_Properties.cur_version + def to_repo_settings(self): + data = {} + data["refresh_version"] = self.refresh_version + data["compression_format"] = self.compression_format + data["force_extended_ram"] = self.force_extended_ram + data["matstack_fix"] = self.matstack_fix + data["write_all"] = self.write_all + return data + + def from_repo_settings(self, data: dict): + set_prop_if_in_data(self, "refresh_version", data, "refresh_version") + set_prop_if_in_data(self, "compression_format", data, "compression_format") + set_prop_if_in_data(self, "force_extended_ram", data, "force_extended_ram") + set_prop_if_in_data(self, "matstack_fix", data, "matstack_fix") + set_prop_if_in_data(self, "write_all", data, "write_all") + def draw_repo_settings(self, layout: UILayout): col = layout.column() if not self.binary_export: @@ -174,7 +190,7 @@ def draw_props(self, layout: UILayout, show_repo_settings: bool = True): if show_repo_settings: self.draw_repo_settings(col) - col.separator() + col.separator() col.prop(self, "show_importing_menus") if self.show_importing_menus: diff --git a/fast64_internal/sm64/settings/repo_settings.py b/fast64_internal/sm64/settings/repo_settings.py index 1129e0f50..a32df8621 100644 --- a/fast64_internal/sm64/settings/repo_settings.py +++ b/fast64_internal/sm64/settings/repo_settings.py @@ -2,7 +2,7 @@ from bpy.types import Scene, UILayout -from ...utility import draw_and_check_tab, prop_split +from ...utility import draw_and_check_tab, prop_split, set_prop_if_in_data def save_sm64_repo_settings(scene: Scene): @@ -18,12 +18,7 @@ def save_sm64_repo_settings(scene: Scene): } sm64_props = scene.fast64.sm64 - data["refresh_version"] = sm64_props.refresh_version - data["compression_format"] = sm64_props.compression_format - data["force_extended_ram"] = sm64_props.force_extended_ram - data["matstack_fix"] = sm64_props.matstack_fix - data["write_all"] = sm64_props.write_all - + data.update(sm64_props.to_repo_settings()) return data @@ -34,13 +29,9 @@ def load_sm64_repo_settings(scene: Scene, data: dict[str, Any]): for layer in range(8): draw_layer = draw_layers.get(str(layer), {}) if "cycle_1" in draw_layer: - setattr(world, f"draw_layer_{layer}_cycle_1", draw_layer["cycle_1"]) + set_prop_if_in_data(world, f"draw_layer_{layer}_cycle_1", draw_layer, "cycle_1") if "cycle_2" in draw_layer: - setattr(world, f"draw_layer_{layer}_cycle_2", draw_layer["cycle_2"]) + set_prop_if_in_data(world, f"draw_layer_{layer}_cycle_2", draw_layer, "cycle_2") sm64_props = scene.fast64.sm64 - sm64_props.refresh_version = data.get("refresh_version", sm64_props.refresh_version) - sm64_props.compression_format = data.get("compression_format", sm64_props.compression_format) - sm64_props.force_extended_ram = data.get("force_extended_ram", sm64_props.force_extended_ram) - sm64_props.matstack_fix = data.get("matstack_fix", sm64_props.matstack_fix) - sm64_props.write_all = data.get("write_all", sm64_props.write_all) + sm64_props.from_repo_settings(data) diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 14f6aea59..aef4ee729 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1896,3 +1896,12 @@ def create_or_get_world(scene: Scene) -> World: WORLD_WARNING_COUNT = 0 print(f'No world in this file, creating world named "Fast64".') return bpy.data.worlds.new("Fast64") + + +def set_if_different(owner: object, prop: str, value): + if getattr(owner, prop) != value: + setattr(owner, prop, value) + + +def set_prop_if_in_data(owner: object, prop_name: str, data: dict, data_name: str): + set_if_different(owner, prop_name, data.get(data_name, getattr(owner, prop_name))) From 3d4cdbe96924e0a36781a51a83fcd0d276ceea10 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 31 Oct 2024 17:40:09 +0000 Subject: [PATCH 12/12] Update utility.py --- fast64_internal/utility.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 5b36a00ad..702ddd697 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1907,4 +1907,5 @@ def set_if_different(owner: object, prop: str, value): def set_prop_if_in_data(owner: object, prop_name: str, data: dict, data_name: str): - set_if_different(owner, prop_name, data.get(data_name, getattr(owner, prop_name))) + if data_name in data: + set_if_different(owner, prop_name, data[data_name])