From 821c4c9cce4060c3f2234e59c18a97b5703d19a1 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 19 Apr 2025 15:02:05 +0100 Subject: [PATCH 01/32] initial work on 8 texture slots (ui, flipbooks, code improvements, uv scroll fixes) todo next: some sm64 scroll clean up since we want that in the individual textures now for clarity. more game mode separation in materials is ideal (and in f3d writer in the case of sm64 tile scroll), oot flipbook upgrade code --- fast64_internal/f3d/f3d_enums.py | 5 - fast64_internal/f3d/f3d_gbi.py | 48 +++--- fast64_internal/f3d/f3d_material.py | 170 +++++++++++----------- fast64_internal/f3d/f3d_parser.py | 11 +- fast64_internal/f3d/f3d_texture_writer.py | 5 +- fast64_internal/f3d/flipbook.py | 42 +++--- fast64_internal/oot/oot_model_classes.py | 39 +++-- fast64_internal/sm64/sm64_f3d_writer.py | 8 +- 8 files changed, 146 insertions(+), 182 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index d9e032c23..7746de1b0 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -351,11 +351,6 @@ ("IA16", "Intensity Alpha 16-bit", "Intensity Alpha 16-bit"), ] -enumTexUV = [ - ("TEXEL0", "Texture 0", "Texture 0"), - ("TEXEL1", "Texture 1", "Texture 1"), -] - texBitSizeInt = { "I4": 4, "IA4": 4, diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index c26263c8e..f5815dc61 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -1892,7 +1892,7 @@ def get_tex_sts_code( def get_tile_scroll_code( variableName: str, scrollData: "FScrollData", textureIndex: int, commandIndex: int ) -> Tuple[str, str]: - scrollInfo: FSetTileSizeScrollField = getattr(scrollData, f"tile_scroll_tex{textureIndex}") + scrollInfo: FSetTileSizeScrollField = scrollData.tile_scrolls[textureIndex] if scrollInfo.s or scrollInfo.t: variables = [] lines = [] @@ -1914,7 +1914,7 @@ def get_tile_scroll_code( def vertexScrollTemplate( fScrollData, name, count, absFunc, signFunc, cosFunc, randomFloatFunc, randomSignFunc, segToVirtualFunc ): - scrollDataFields = fScrollData.fields[0] + scrollDataFields = fScrollData.fields if scrollDataFields[0].animType == "None" and scrollDataFields[1].animType == "None": return "" data = [ @@ -2369,7 +2369,7 @@ def processTexRefNonCITextures(self, fMaterial: FMaterial, material: bpy.types.M image), for creating image / palette keys - an object containing info about the additional textures, or None """ - texProp = getattr(material.f3d_mat, f"tex{index}") + texProp = material.f3d_mat.all_textures[index] imDependencies = [] if texProp.tex is None else [texProp.tex] return imDependencies, None @@ -2389,7 +2389,7 @@ def processTexRefCITextures(self, fMaterial: FMaterial, material: bpy.types.Mate - an object containing info about the additional textures, or None - the palette to use (or None) """ - texProp = getattr(material.f3d_mat, f"tex{index}") + texProp = material.f3d_mat.all_textures[index] imDependencies = [] if texProp.tex is None else [texProp.tex] return imDependencies, None, None @@ -3006,10 +3006,9 @@ def __init__(self): class FScrollData: def __init__(self): - self.fields = [[FScrollDataField(), FScrollDataField()], [FScrollDataField(), FScrollDataField()]] + self.fields = [FScrollDataField(), FScrollDataField()] self.dimensions = [0, 0] - self.tile_scroll_tex0 = FSetTileSizeScrollField() - self.tile_scroll_tex1 = FSetTileSizeScrollField() + self.tile_scrolls: list[FSetTileSizeScrollField] = [] def get_f3d_mat_from_version(material: bpy.types.Material): @@ -3040,25 +3039,16 @@ def __init__(self, name, DLFormat): self.texPaletteIndex = [0, 0] def getScrollData(self, material, dimensions): - self.getScrollDataField(material, 0, 0) - self.getScrollDataField(material, 0, 1) - self.getScrollDataField(material, 1, 0) - self.getScrollDataField(material, 1, 1) + self.getScrollDataField(material, 0) + self.getScrollDataField(material, 1) self.scrollData.dimensions = dimensions self.getSetTileSizeScrollData(material) - def getScrollDataField(self, material, texIndex, fieldIndex): - UVanim0 = material.f3d_mat.UVanim0 if material.mat_ver > 3 else material.UVanim - UVanim1 = material.f3d_mat.UVanim1 if material.mat_ver > 3 else material.UVanim_tex1 + def getScrollDataField(self, material, fieldIndex): + UVanim0 = material.f3d_mat.UVanim0 + field = getattr(UVanim0, "xyz"[fieldIndex]) - if texIndex == 0: - field = getattr(UVanim0, "xyz"[fieldIndex]) - elif texIndex == 1: - field = getattr(UVanim1, "xyz"[fieldIndex]) - else: - raise PluginError("Invalid texture index.") - - scrollField = self.scrollData.fields[texIndex][fieldIndex] + scrollField = self.scrollData.fields[fieldIndex] scrollField.animType = field.animType scrollField.speed = field.speed @@ -3071,13 +3061,13 @@ def getScrollDataField(self, material, texIndex, fieldIndex): def getSetTileSizeScrollData(self, material): tex0 = get_f3d_mat_from_version(material).tex0 tex1 = get_f3d_mat_from_version(material).tex1 - - self.scrollData.tile_scroll_tex0.s = tex0.tile_scroll.s - self.scrollData.tile_scroll_tex0.t = tex0.tile_scroll.t - self.scrollData.tile_scroll_tex0.interval = tex0.tile_scroll.interval - self.scrollData.tile_scroll_tex1.s = tex1.tile_scroll.s - self.scrollData.tile_scroll_tex1.t = tex1.tile_scroll.t - self.scrollData.tile_scroll_tex1.interval = tex1.tile_scroll.interval + self.scrollData.tile_scrolls = [] + for tex_prop in material.f3d_mat.all_textures: + tile_scroll = FSetTileSizeScrollField() + tile_scroll.s = tex_prop.tile_scroll.s + tile_scroll.t = tex_prop.tile_scroll.t + tile_scroll.interval = tex_prop.tile_scroll.interval + self.scrollData.tile_scrolls.append(tile_scroll) def get_ptr_addresses(self, f3d): addresses = self.material.get_ptr_addresses(f3d) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 3acbc9aaa..03f543ab2 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -501,7 +501,8 @@ def all_combiner_uses(f3d_mat: "F3DMaterialProperty") -> dict[str, bool]: "Primitive": combiner_uses( f3d_mat, ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], - ), + ) + or f3d_mat.rdp_settings.g_mdsft_textlod == "G_TL_LOD", "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"]), "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False), "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False) @@ -1243,19 +1244,21 @@ def checkDrawLayersWarnings(self, f3dMat: "F3DMaterialProperty", useDict: Dict[s noticeBox.label(text="Mesh must have two Color Attribute (vtx color) layers.", icon="IMAGE_RGB_ALPHA") noticeBox.label(text='They must be called "Col" and "Alpha".', icon="IMAGE_ALPHA") - def checkDrawMixedCIWarning(self, layout, useDict, f3dMat): - useTex0 = useDict["Texture 0"] and f3dMat.tex0.tex_set - useTex1 = useDict["Texture 1"] and f3dMat.tex1.tex_set - if not useTex0 or not useTex1: + def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): + tlut_modes = set(tex.tlut_mode for tex in f3d_mat.set_textures.values()) + if len(tlut_modes) <= 1: + return + if "G_TT_NONE" in tlut_modes: + multilineLabel(layout, "Can't mix CI and non-CI textures.", icon="ERROR") return - isTex0CI = f3dMat.tex0.tex_format[:2] == "CI" - isTex1CI = f3dMat.tex1.tex_format[:2] == "CI" - if isTex0CI != isTex1CI: - layout.box().column().label(text="Can't have one CI tex and one non-CI.", icon="ERROR") - if isTex0CI and isTex1CI and (f3dMat.tex0.ci_format != f3dMat.tex1.ci_format): - layout.box().column().label(text="Two CI textures must use the same CI format.", icon="ERROR") - - def draw_simple(self, f3dMat, material, layout, context): + else: + text = "CI textures must use the same CI format." + for tlut in tlut_modes: + textures = [str(i) for i, tex in f3d_mat.set_textures.items() if tex.tlut_mode == tlut] + text += f"\n{tlut.lstrip('G_TT_')}: Texture{'s' if len(textures) > 1 else ''} {', '.join(textures)}" + multilineLabel(layout, text, icon="ERROR") + + def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout, context): f3d = get_F3D_GBI() self.ui_uvCheck(layout, context) @@ -1264,17 +1267,11 @@ def draw_simple(self, f3dMat, material, layout, context): self.checkDrawLayersWarnings(f3dMat, useDict, layout) - useMultitexture = useDict["Texture 0"] and useDict["Texture 1"] and f3dMat.tex0.tex_set and f3dMat.tex1.tex_set - - self.checkDrawMixedCIWarning(inputCol, useDict, f3dMat) - canUseLargeTextures = material.mat_ver > 3 and material.f3d_mat.use_large_textures - if useDict["Texture 0"] and f3dMat.tex0.tex_set: - ui_image(canUseLargeTextures, inputCol, material, f3dMat.tex0, "Texture 0", False) + self.draw_ci_warnings(inputCol, f3dMat) + for i, tex in f3dMat.set_textures.items(): + ui_image(f3dMat.use_large_textures, inputCol, material, tex, f"Texture {i}", False) - if useDict["Texture 1"] and f3dMat.tex1.tex_set: - ui_image(canUseLargeTextures, inputCol, material, f3dMat.tex1, "Texture 1", False) - - if useMultitexture: + if len(f3dMat.set_textures) > 1: inputCol.prop(f3dMat, "uv_basis", text="UV Basis") if useDict["Texture"]: @@ -1304,7 +1301,7 @@ def draw_simple(self, f3dMat, material, layout, context): self.ui_misc(f3dMat, inputCol, False) - def draw_full(self, f3dMat, material, layout: UILayout, context): + def draw_full(self, f3dMat: "F3DMaterialProperty", material, layout: UILayout, context): layout.row().prop(material, "menu_tab", expand=True) menuTab = material.menu_tab useDict = all_combiner_uses(f3dMat) @@ -1359,17 +1356,11 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl inputCol = layout.column() - useMultitexture = useDict["Texture 0"] and useDict["Texture 1"] - - self.checkDrawMixedCIWarning(inputCol, useDict, f3dMat) - canUseLargeTextures = material.mat_ver > 3 and material.f3d_mat.use_large_textures - if useDict["Texture 0"]: - ui_image(canUseLargeTextures, inputCol, material, f3dMat.tex0, "Texture 0", True) - - if useDict["Texture 1"]: - ui_image(canUseLargeTextures, inputCol, material, f3dMat.tex1, "Texture 1", True) + self.draw_ci_warnings(inputCol, f3dMat) + for i, tex in f3dMat.used_textures.items(): + ui_image(f3dMat.use_large_textures, inputCol, material, tex, f"Texture {i}", True) - if useMultitexture: + if len(f3dMat.set_textures) > 1: inputCol.prop(f3dMat, "uv_basis", text="UV Basis") if useDict["Texture"]: @@ -1494,7 +1485,9 @@ def ui_tileScroll(tex, name, layout): row.prop(tex.tile_scroll, "interval", text="Interval:") -def ui_procAnimVecEnum(material, procAnimVec, layout, name, vecType, useDropdown, useTex0, useTex1): +def ui_procAnimVecEnum( + f3d_mat: "F3DMaterialProperty", procAnimVec, layout, name, vecType, useDropdown, useTex0, useTex1 +): layout = layout.box() box = layout.column() if useDropdown: @@ -1525,12 +1518,8 @@ def ui_procAnimVecEnum(material, procAnimVec, layout, name, vecType, useDropdown if useTex0 or useTex1: layout.box().label(text="SM64 SetTileSize Texture Scroll") - - if useTex0: - ui_tileScroll(material.tex0, "Texture 0 Speed", layout) - - if useTex1: - ui_tileScroll(material.tex1, "Texture 1 Speed", layout) + for i, tex in f3d_mat.set_textures.items(): + ui_tileScroll(tex, f"Texture {i} Speed", layout) def ui_procAnimFieldEnum(procAnimField, layout, name, overrideName): @@ -2290,9 +2279,11 @@ def update_tex_values_manual(material: Material, context, prop_path=None): useDict = all_combiner_uses(f3dMat) f3dMat.rdp_settings.g_mdsft_textlut = get_textlut_mode(f3dMat) + if f3dMat.uv_basis == "": + f3dMat.uv_basis = str(max(f3dMat.set_textures.keys()) if f3dMat.set_textures else -1) - tex0_used = useDict["Texture 0"] and f3dMat.tex0.tex is not None - tex1_used = useDict["Texture 1"] and f3dMat.tex1.tex is not None + tex0_used = useDict["Texture 0"] + tex1_used = useDict["Texture 1"] if not tex0_used and not tex1_used: texture_settings.mute = True @@ -3075,8 +3066,6 @@ def ui_image( if showCheckBox: prop_input_name.prop(textureProp, "tex_set", text="Set Texture") - else: - prop_input_name.label(text=name) texIndex = name[-1] prop_input.prop(textureProp, "use_tex_reference") @@ -3084,8 +3073,7 @@ def ui_image( prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") if textureProp.tex_format[:2] == "CI": - flipbook = getattr(material.flipbookGroup, "flipbook" + texIndex) - if flipbook is None or not flipbook.enable: + if textureProp.flipbook is None or not textureProp.flipbook.enable: prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") @@ -4072,42 +4060,27 @@ class AddPresetF3D(AddPresetBase, Operator): "Custom", # "Shaded Texture", ] - + tex_ignore_props = [ + "tex", + "tex_format", + "ci_format", + "use_tex_reference", + "tex_reference", + "tex_reference_size", + "pal_reference", + "pal_reference_size", + "S", + "T", + "menu", + "autoprop", + "save_large_texture", + "tile_scroll", + "tile_scroll.s", + "tile_scroll.t", + "tile_scroll.interval", + ] ignore_props = { - "f3d_mat.tex0.tex", - "f3d_mat.tex0.tex_format", - "f3d_mat.tex0.ci_format", - "f3d_mat.tex0.use_tex_reference", - "f3d_mat.tex0.tex_reference", - "f3d_mat.tex0.tex_reference_size", - "f3d_mat.tex0.pal_reference", - "f3d_mat.tex0.pal_reference_size", - "f3d_mat.tex0.S", - "f3d_mat.tex0.T", - "f3d_mat.tex0.menu", - "f3d_mat.tex0.autoprop", - "f3d_mat.tex0.save_large_texture", - "f3d_mat.tex0.tile_scroll", - "f3d_mat.tex0.tile_scroll.s", - "f3d_mat.tex0.tile_scroll.t", - "f3d_mat.tex0.tile_scroll.interval", - "f3d_mat.tex1.tex", - "f3d_mat.tex1.tex_format", - "f3d_mat.tex1.ci_format", - "f3d_mat.tex1.use_tex_reference", - "f3d_mat.tex1.tex_reference", - "f3d_mat.tex1.tex_reference_size", - "f3d_mat.tex1.pal_reference", - "f3d_mat.tex1.pal_reference_size", - "f3d_mat.tex1.S", - "f3d_mat.tex1.T", - "f3d_mat.tex1.menu", - "f3d_mat.tex1.autoprop", - "f3d_mat.tex1.save_large_texture", - "f3d_mat.tex1.tile_scroll", - "f3d_mat.tex1.tile_scroll.s", - "f3d_mat.tex1.tile_scroll.t", - "f3d_mat.tex1.tile_scroll.interval", + *[f"f3d_mat.tex{i}.{prop}" for prop in tex_ignore_props for i in range(8)], "f3d_mat.tex_scale", "f3d_mat.scale_autoprop", "f3d_mat.uv_basis", @@ -4365,8 +4338,10 @@ class F3DMaterialProperty(PropertyGroup): ) uv_basis: bpy.props.EnumProperty( name="UV Basis", - default="TEXEL0", - items=enumTexUV, + items=lambda self, context: [ + (str(i), f"Texture {i}", f"Use the size of texture {i} for UVs") for i in self.set_textures.keys() + ] + or [(str(-1), "", "")], update=update_tex_values, ) @@ -4377,7 +4352,6 @@ class F3DMaterialProperty(PropertyGroup): # Texture animation menu_procAnim: bpy.props.BoolProperty() UVanim0: bpy.props.PointerProperty(type=ProcAnimVectorProperty) - UVanim1: bpy.props.PointerProperty(type=ProcAnimVectorProperty) # material textures tex_scale: bpy.props.FloatVectorProperty( @@ -4390,6 +4364,12 @@ class F3DMaterialProperty(PropertyGroup): ) tex0: bpy.props.PointerProperty(type=TextureProperty, name="tex0") tex1: bpy.props.PointerProperty(type=TextureProperty, name="tex1") + tex2: bpy.props.PointerProperty(type=TextureProperty, name="tex2") + tex3: bpy.props.PointerProperty(type=TextureProperty, name="tex3") + tex4: bpy.props.PointerProperty(type=TextureProperty, name="tex4") + tex5: bpy.props.PointerProperty(type=TextureProperty, name="tex5") + tex6: bpy.props.PointerProperty(type=TextureProperty, name="tex6") + tex7: bpy.props.PointerProperty(type=TextureProperty, name="tex7") # Should Set? @@ -4673,16 +4653,30 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) + @property + def all_textures(self) -> list[TextureProperty]: + return tuple(getattr(self, f"tex{i}") for i in range(8)) + + @property + def used_textures(self) -> dict[int, TextureProperty]: + self.rdp_settings: RDPSettings + if self.rdp_settings.g_mdsft_textlod == "G_TL_LOD": + return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} + use_dict = all_combiner_uses(self) + return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} + + @property + def set_textures(self): + return {i: tex for i, tex in self.used_textures.items() if tex.tex_set} + def key(self) -> F3DMaterialHash: useDefaultLighting = self.set_lights and self.use_default_lighting return ( self.scale_autoprop, self.uv_basis, self.UVanim0.key(), - self.UVanim1.key(), tuple([round(value, 4) for value in self.tex_scale]), - self.tex0.key(), - self.tex1.key(), + tuple((i, tex.key()) for i, tex in self.set_textures.items()), self.rdp_settings.key(), self.draw_layer.key(), self.use_large_textures, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index b91154916..dd873a3b6 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -783,7 +783,7 @@ def handleApplyTLUT( # however we always want to record the changing tlut for texture references. def applyTLUTToIndex(self, index): mat = self.mat() - texProp = getattr(mat, "tex" + str(index)) + texProp = mat.all_textures[index] combinerUses = all_combiner_uses(mat) if texProp.tex_format[:2] == "CI": @@ -1042,8 +1042,7 @@ def setTLUTMode(self, flags): if not isinstance(flags, int): flags = math_eval(flags, self.f3d) tlut_mode = flags & (0b11 << self.f3d.G_MDSFT_TEXTLUT) - for index in range(2): - texProp = getattr(mat, "tex" + str(index)) + for texProp in mat.all_textures: if tlut_mode == self.f3d.G_TT_IA16: texProp.ci_format = "IA16" elif tlut_mode == self.f3d.G_TT_RGBA16: @@ -1431,7 +1430,7 @@ def handleTextureReference( tileSettings: DPSetTile, data: str, ): - texProp = getattr(material.f3d_mat, "tex" + str(index)) + texProp = material.f3d_mat.all_textures[index] texProp.tex = None texProp.use_tex_reference = True texProp.tex_reference = name @@ -1439,7 +1438,7 @@ def handleTextureReference( # add to this by overriding in a parent context, to handle clearing settings related to previous texture references. def handleTextureValue(self, material: bpy.types.Material, image: bpy.types.Image, index: int): - texProp = getattr(material.f3d_mat, "tex" + str(index)) + texProp = material.f3d_mat.all_textures[index] texProp.tex = image texProp.use_tex_reference = False size = texProp.tex.size @@ -1447,7 +1446,7 @@ def handleTextureValue(self, material: bpy.types.Material, image: bpy.types.Imag def applyTileToMaterial(self, index, tileSettings, tileSizeSettings, dlData: str): mat = self.mat() - texProp = getattr(mat, "tex" + str(index)) + texProp = mat.all_textures[index] name = self.tmemDict[tileSettings.tmem] image = self.textureData[name] diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index cdedea1e7..a2820e166 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -417,8 +417,7 @@ def fromMat(self, index: int, f3dMat: F3DMaterialProperty) -> bool: if not useDict["Texture " + str(index)]: return True - texProp = getattr(f3dMat, "tex" + str(index)) - return self.fromProp(texProp, index) + return self.fromProp(f3dMat.all_textures[index], index) def fromProp(self, texProp: TextureProperty, index: int, ignore_tex_set=False) -> bool: self.indexInMat = index @@ -1054,7 +1053,7 @@ def saveTextureTile( tileCommand = DPSetTile(fmt, siz, line, tmem, rendertile, pal, cmt, maskt, shiftt, cms, masks, shifts) tileSizeCommand = DPSetTileSize(rendertile, sl, tl, sh, th) - scrollInfo = getattr(fMaterial.scrollData, f"tile_scroll_tex{rendertile}") + scrollInfo = fMaterial.scrollData.tile_scrolls[rendertile] if scrollInfo.s or scrollInfo.t: tileSizeCommand.tags |= GfxTag.TileScroll0 if rendertile == 0 else GfxTag.TileScroll1 diff --git a/fast64_internal/f3d/flipbook.py b/fast64_internal/f3d/flipbook.py index 86e9f3bdb..8ebd4ef31 100644 --- a/fast64_internal/f3d/flipbook.py +++ b/fast64_internal/f3d/flipbook.py @@ -47,8 +47,8 @@ def usesFlipbook( checkEnable: bool, checkFlipbookReference: Optional[Callable[[str], bool]], ) -> bool: - texProp = getattr(material.f3d_mat, f"tex{index}") - if all_combiner_uses(material.f3d_mat)["Texture " + str(index)] and texProp.use_tex_reference: + texProp = material.f3d_mat.used_textures.get(index) + if texProp and texProp.use_tex_reference: return ( checkFlipbookReference is not None and checkFlipbookReference(texProp.tex_reference) @@ -121,7 +121,7 @@ class AddFlipbookTexture(bpy.types.Operator): def execute(self, context): material = context.material - flipbook = getattr(material.flipbookGroup, "flipbook" + str(self.combinerTexIndex)) + flipbook = material.f3d_mat.all_textures[self.combinerTexIndex].flipbook flipbook.textures.add() flipbook.textures.move(len(flipbook.textures) - 1, self.arrayIndex) self.report({"INFO"}, "Success!") @@ -137,7 +137,7 @@ class RemoveFlipbookTexture(bpy.types.Operator): def execute(self, context): material = context.material - flipbook = getattr(material.flipbookGroup, "flipbook" + str(self.combinerTexIndex)) + flipbook = material.f3d_mat.all_textures[self.combinerTexIndex].flipbook flipbook.textures.remove(self.arrayIndex) self.report({"INFO"}, "Success!") return {"FINISHED"} @@ -153,7 +153,7 @@ class MoveFlipbookTexture(bpy.types.Operator): def execute(self, context): material = context.material - flipbook = getattr(material.flipbookGroup, "flipbook" + str(self.combinerTexIndex)) + flipbook = material.f3d_mat.all_textures[self.combinerTexIndex].flipbook flipbook.textures.move(self.arrayIndex, self.arrayIndex + self.offset) self.report({"INFO"}, "Success!") return {"FINISHED"} @@ -168,8 +168,7 @@ class VisualizeFlipbookTexture(bpy.types.Operator): def execute(self, context): material = context.material - flipbook = getattr(material.flipbookGroup, "flipbook" + str(self.combinerTexIndex)) - texProp = getattr(material.f3d_mat, "tex" + str(self.combinerTexIndex)) + flipbook = material.f3d_mat.all_textures[self.combinerTexIndex].flipbook setTexNodeImage(context.material, self.combinerTexIndex, self.arrayIndex) @@ -190,11 +189,6 @@ class FlipbookProperty(bpy.types.PropertyGroup): textures: bpy.props.CollectionProperty(type=FlipbookImagePointerProperty) -class FlipbookGroupProperty(bpy.types.PropertyGroup): - flipbook0: bpy.props.PointerProperty(type=FlipbookProperty) - flipbook1: bpy.props.PointerProperty(type=FlipbookProperty) - - def drawFlipbookProperty(layout: bpy.types.UILayout, flipbookProp: FlipbookProperty, index: int): box = layout.box().column() box.prop(flipbookProp, "enable", text="Export Flipbook Textures " + str(index)) @@ -214,11 +208,11 @@ def drawFlipbookGroupProperty( layout.box().column().label(text="Flipbook Properties") if drawFlipbookRequirementMessage is not None: drawFlipbookRequirementMessage(layout) - for i in range(2): - flipbook = getattr(material.flipbookGroup, "flipbook" + str(i)) + for i, tex_prop in enumerate(material.f3d_mat.all_textures): + flipbook = tex_prop.flipbook if usesFlipbook(material, flipbook, i, False, checkFlipbookReference): drawFlipbookProperty(layout.column(), flipbook, i) - if getattr(material.f3d_mat, "tex" + str(i)).tex_format[:2] == "CI": + if tex_prop.tex_format[:2] == "CI": layout.label(text="New shared CI palette will be generated.", icon="RENDERLAYERS") @@ -237,11 +231,10 @@ def ootFlipbookAnimUpdate(self, armatureObj: bpy.types.Object, segment: str, ind if child.type != "MESH": continue for material in child.data.materials: - for i in range(2): - flipbook = getattr(material.flipbookGroup, "flipbook" + str(i)) - texProp = getattr(material.f3d_mat, "tex" + str(i)) + for i, tex_prop in enumerate(material.f3d_mat.all_textures): + flipbook = tex_prop.flipbook if usesFlipbook(material, flipbook, i, True, ootFlipbookReferenceIsValid): - match = re.search(f"0x0([0-9A-F])000000", texProp.tex_reference) + match = re.search(f"0x0([0-9A-F])000000", tex_prop.tex_reference) if match is None: continue if match.group(1) == segment: @@ -302,8 +295,11 @@ def draw(self, context): def setTexNodeImage(material: bpy.types.Material, texIndex: int, flipbookIndex: int): - flipbook = getattr(material.flipbookGroup, "flipbook" + str(texIndex)) - for texNode in iter_tex_nodes(material.node_tree, texIndex): + flipbook = material.f3d_mat.all_textures[texIndex].flipbook + nodes = list(iter_tex_nodes(material.node_tree, texIndex)) + if not nodes: + return + for texNode in nodes: if texNode.image is not flipbook.textures[flipbookIndex].image: texNode.image = flipbook.textures[flipbookIndex].image @@ -315,7 +311,6 @@ def setTexNodeImage(material: bpy.types.Material, texIndex: int, flipbookIndex: MoveFlipbookTexture, VisualizeFlipbookTexture, FlipbookProperty, - FlipbookGroupProperty, Flipbook_MaterialPanel, ] @@ -325,7 +320,7 @@ def flipbook_register(): register_class(cls) bpy.app.handlers.frame_change_pre.append(flipbookAnimHandler) - bpy.types.Material.flipbookGroup = bpy.props.PointerProperty(type=FlipbookGroupProperty) + TextureProperty.flipbook = bpy.props.PointerProperty(type=FlipbookProperty) def flipbook_unregister(): @@ -333,4 +328,3 @@ def flipbook_unregister(): unregister_class(cls) bpy.app.handlers.frame_change_pre.remove(flipbookAnimHandler) - del bpy.types.Material.flipbookGroup diff --git a/fast64_internal/oot/oot_model_classes.py b/fast64_internal/oot/oot_model_classes.py index ce3fe2f45..84e2f2c2b 100644 --- a/fast64_internal/oot/oot_model_classes.py +++ b/fast64_internal/oot/oot_model_classes.py @@ -149,18 +149,16 @@ def raiseErr(subMsg): ) model.flipbooks.append(flipbook) - def validateImages(self, material: bpy.types.Material, index: int): - flipbookProp = getattr(material.flipbookGroup, f"flipbook{index}") - texProp = getattr(material.f3d_mat, f"tex{index}") + def validateImages(self, tex_prop: "TextureProperty"): allImages = [] - refSize = (texProp.tex_reference_size[0], texProp.tex_reference_size[1]) - for flipbookTexture in flipbookProp.textures: + refSize = (tex_prop.tex_reference_size[0], tex_prop.tex_reference_size[1]) + for flipbookTexture in tex_prop.flipbook.textures: if flipbookTexture.image is None: - raise PluginError(f"Flipbook for {material.name} has a texture array item that has not been set.") + raise PluginError("Flipbook has a texture array item that has not been set.") imSize = (flipbookTexture.image.size[0], flipbookTexture.image.size[1]) if imSize != refSize: raise PluginError( - f"In {material.name}: texture reference size is {refSize}, " + f"Texture reference size is {refSize}, " + f"but flipbook image {flipbookTexture.image.filepath} size is {imSize}." ) if flipbookTexture.image not in allImages: @@ -170,8 +168,8 @@ def validateImages(self, material: bpy.types.Material, index: int): def processTexRefCITextures(self, fMaterial: FMaterial, material: bpy.types.Material, index: int) -> FImage: # print("Processing flipbook...") model = self.getFlipbookOwner() - flipbookProp = getattr(material.flipbookGroup, f"flipbook{index}") - texProp = getattr(material.f3d_mat, f"tex{index}") + texProp = material.f3d_mat.all_textures[index] + flipbookProp = texProp.flipbook if not usesFlipbook(material, flipbookProp, index, True, ootFlipbookReferenceIsValid): return super().processTexRefCITextures(fMaterial, material, index) if len(flipbookProp.textures) == 0: @@ -180,7 +178,7 @@ def processTexRefCITextures(self, fMaterial: FMaterial, material: bpy.types.Mate flipbook = TextureFlipbook(flipbookProp.name, flipbookProp.exportMode, [], []) pal = [] - allImages = self.validateImages(material, index) + allImages = self.validateImages(texProp) for flipbookTexture in flipbookProp.textures: # print(f"Texture: {str(flipbookTexture.image)}") imageName, filename = getTextureNamesFromImage(flipbookTexture.image, texProp.tex_format, model) @@ -236,15 +234,15 @@ def writeTexRefCITextures( def processTexRefNonCITextures(self, fMaterial: FMaterial, material: bpy.types.Material, index: int): model = self.getFlipbookOwner() - flipbookProp = getattr(material.flipbookGroup, f"flipbook{index}") - texProp = getattr(material.f3d_mat, f"tex{index}") + texProp = material.f3d_mat.all_textures[index] + flipbookProp = texProp.flipbook if not usesFlipbook(material, flipbookProp, index, True, ootFlipbookReferenceIsValid): return super().processTexRefNonCITextures(fMaterial, material, index) if len(flipbookProp.textures) == 0: raise PluginError(f"{str(material)} cannot have a flipbook material with no flipbook textures.") flipbook = TextureFlipbook(flipbookProp.name, flipbookProp.exportMode, [], []) - allImages = self.validateImages(material, index) + allImages = self.validateImages(texProp) for flipbookTexture in flipbookProp.textures: # print(f"Texture: {str(flipbookTexture.image)}") # Can't use saveOrGetTextureDefinition because the way it gets the @@ -416,8 +414,8 @@ def clearMaterial(self): self.isBillboard = False # Don't clear ootMaterial, some skeletons (Link) require dynamic material calls to be preserved between limbs - clearOOTFlipbookProperty(self.materialContext.flipbookGroup.flipbook0) - clearOOTFlipbookProperty(self.materialContext.flipbookGroup.flipbook1) + for tex in self.materialContext.f3d_mat.all_textures: + clearOOTFlipbookProperty(tex.flipbook) F3DContext.clearMaterial(self) def postMaterialChanged(self): @@ -433,15 +431,15 @@ def handleTextureReference( data: str, ): # check for texture arrays. - clearOOTFlipbookProperty(getattr(material.flipbookGroup, "flipbook" + str(index))) + clearOOTFlipbookProperty(material.f3d_mat.all_textures[index].flipbook) match = re.search(f"(0x0[0-9a-fA-F])000000", name) if match: segment = int(match.group(1), 16) flipbookKey = (segment, material.f3d_mat.draw_layer.oot) if flipbookKey in self.flipbooks: flipbook = self.flipbooks[flipbookKey] - - flipbookProp = getattr(material.flipbookGroup, "flipbook" + str(index)) + texProp = material.f3d_mat.all_textures[index] + flipbookProp = texProp.flipbook flipbookProp.enable = True flipbookProp.exportMode = flipbook.exportMode if flipbookProp.exportMode == "Array": @@ -465,7 +463,6 @@ def handleTextureReference( if flipbookProp.exportMode == "Individual": flipbookProp.textures[-1].name = textureName - texProp = getattr(material.f3d_mat, "tex" + str(index)) texProp.tex = flipbookProp.textures[0].image # for visual purposes only, will be ignored texProp.use_tex_reference = True texProp.tex_reference = name @@ -475,7 +472,7 @@ def handleTextureReference( super().handleTextureReference(name, image, material, index, tileSettings, data) def handleTextureValue(self, material: bpy.types.Material, image: bpy.types.Image, index: int): - clearOOTFlipbookProperty(getattr(material.flipbookGroup, "flipbook" + str(index))) + clearOOTFlipbookProperty(material.f3d_mat.all_textures[index].flipbook) super().handleTextureValue(material, image, index) def handleApplyTLUT( @@ -485,7 +482,7 @@ def handleApplyTLUT( tlut: bpy.types.Image, index: int, ): - flipbook = getattr(material.flipbookGroup, "flipbook" + str(index)) + flipbook = texProp.flipbook if usesFlipbook(material, flipbook, index, True, ootFlipbookReferenceIsValid): # Don't apply TLUT to texProp.tex, as it is the same texture as the first flipbook texture. # Make sure to check if tlut is already applied (ex. LOD skeleton uses same flipbook textures) diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 43452b17d..01fec3177 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -157,7 +157,7 @@ def vertexScrollToC(self, fMaterial: FMaterial, vtxListName: str, vtxCount: int) "segmented_to_virtual", ) - scrollDataFields = fScrollData.fields[0] + scrollDataFields = fScrollData.fields if not ((scrollDataFields[0].animType == "None") and (scrollDataFields[1].animType == "None")): funcName = f"scroll_{vtxListName}" data.header = f"extern void {funcName}();\n" @@ -931,11 +931,7 @@ def draw(self, context): material = context.material col = layout.column() - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - useDict = all_combiner_uses(f3dMat) + useDict = all_combiner_uses(material.f3d_mat) if useDict["Texture"]: ui_procAnim(material, col, useDict["Texture 0"], useDict["Texture 1"], "SM64 UV Texture Scroll", False) From 74533db2f65f6a45b62fae119933f7d2303046fd Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 21 Apr 2025 22:39:26 +0100 Subject: [PATCH 02/32] some more neat UI code for no load textures --- fast64_internal/f3d/f3d_material.py | 193 +++++++++++++++++++--------- 1 file changed, 134 insertions(+), 59 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 03f543ab2..25405532c 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -751,16 +751,17 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input.enabled = dataHolder.set_blend -def tmemUsageUI(layout, textureProp): - tex = textureProp.tex - if tex is not None and tex.size[0] > 0 and tex.size[1] > 0: - tmemUsage = getTmemWordUsage(textureProp.tex_format, tex.size[0], tex.size[1]) * 8 - tmemMax = getTmemMax(textureProp.tex_format) - layout.label(text="TMEM Usage: " + str(tmemUsage) + " / " + str(tmemMax) + " bytes") - if tmemUsage > tmemMax: - tmemSizeWarning = layout.box() - tmemSizeWarning.label(text="WARNING: Texture size is too large.") - tmemSizeWarning.label(text="Note that width will be internally padded to 64 bit boundaries.") +def tmemUsageUI(layout, textureProp: "TextureProperty"): + tex_size = textureProp.size + tmemUsage = getTmemWordUsage(textureProp.tex_format, tex_size[0], tex_size[1]) * 8 + tmemMax = getTmemMax(textureProp.tex_format) + layout.label(text="TMEM Usage: " + str(tmemUsage) + " / " + str(tmemMax) + " bytes") + if tmemUsage > tmemMax: + multilineLabel( + layout.box(), + "WARNING: Texture size is too large.\nNote that width will be internally padded to 64 bit boundaries.", + icon="ERROR", + ) # UI Assumptions: @@ -2852,7 +2853,7 @@ def update_tex_field_prop(self: Property, context: Context): prop_path = self.path_from_id() tex_property, tex_index = get_tex_prop_from_path(material, prop_path) - tex_size = tex_property.get_tex_size() + tex_size = tex_property.size if tex_size[0] > 0 and tex_size[1] > 0: update_tex_values_field(material, tex_property, tex_size, tex_index) @@ -2867,7 +2868,7 @@ def toggle_auto_prop(self, context: Context): prop_path = self.path_from_id() tex_property, tex_index = get_tex_prop_from_path(material, prop_path) if tex_property.autoprop: - tex_size = tuple([s for s in tex_property.get_tex_size()]) + tex_size = tuple([s for s in tex_property.size]) if tex_size[0] > 0 and tex_size[1] > 0: update_tex_values_field(material, tex_property, tex_size, tex_index) @@ -2945,10 +2946,22 @@ class TextureProperty(PropertyGroup): T: bpy.props.PointerProperty(type=TextureFieldProperty) use_tex_reference: bpy.props.BoolProperty( - name="Use Texture Reference", + name="Reference", default=False, update=update_tex_values, ) + load_tex: bpy.props.BoolProperty( + name="Load Texture", + default=True, + update=update_tex_values, + ) + tex_index: bpy.props.IntProperty( + name="Texture Index", + default=0, + min=0, + max=7, + update=update_tex_values, + ) tex_reference: bpy.props.StringProperty( name="Texture Reference", default="0x08000000", @@ -2960,6 +2973,31 @@ class TextureProperty(PropertyGroup): default=(32, 32), update=update_tex_values, ) + + use_pal_reference: bpy.props.BoolProperty( + name="Reference", + default=False, + update=update_tex_values, + ) + load_pal: bpy.props.BoolProperty( + name="Load Palette", + default=True, + update=update_tex_values, + ) + pal_index: bpy.props.IntProperty( + name="Palette Index", + default=0, + min=0, + max=7, + update=update_tex_values, + ) + pal: bpy.props.PointerProperty( + type=Image, + name="Palette", + description="Reference pallete, the texture will be quantized and indexed against this palette if its set,\n" + "otherwise a greyscale version of the texture will be used as indices to the pallete", + update=update_tex_values, + ) pal_reference: bpy.props.StringProperty( name="Palette Reference", default="0x08000000", @@ -2991,13 +3029,20 @@ def is_ci(self): def tlut_mode(self): return f"G_TT_{self.ci_format if self.is_ci else 'NONE'}" - def get_tex_size(self) -> list[int]: - if self.tex or self.use_tex_reference: + @property + def has_texture(self): + return self.load_tex and not self.use_tex_reference + + @property + def has_palette(self): + return self.load_pal and self.has_texture and not self.use_pal_reference + + @property + def size(self) -> tuple[int]: + if self.has_texture: if self.tex is not None: - return self.tex.size - else: - return self.tex_reference_size - return [0, 0] + return tuple(self.tex.size) + return tuple(self.tex_reference_size) def key(self): texSet = self.tex_set @@ -3008,15 +3053,18 @@ def key(self): self.tex if texSet else None, self.tex_format if texSet else None, self.ci_format if texSet and isCI else None, + self.size if texSet else None, self.S.key() if texSet else None, self.T.key() if texSet else None, self.autoprop if texSet else None, self.tile_scroll.key() if texSet else None, self.use_tex_reference if texSet else None, + self.use_pal_reference if texSet and isCI else None, self.tex_reference if texSet and useRef else None, - self.tex_reference_size if texSet and useRef else None, self.pal_reference if texSet and useRef and isCI else None, self.pal_reference_size if texSet and useRef and isCI else None, + self.load_tex if texSet else None, + self.load_pal if texSet and isCI else None, ) @@ -3056,42 +3104,38 @@ def ui_image( ): inputGroup = layout.box().column() - inputGroup.prop( - textureProp, "menu", text=name + " Properties", icon="TRIA_DOWN" if textureProp.menu else "TRIA_RIGHT" - ) + row = inputGroup.row() + row.prop(textureProp, "menu", text="", icon="TRIA_DOWN" if textureProp.menu else "TRIA_RIGHT", emboss=False) + if showCheckBox: + row.prop(textureProp, "tex_set", text=f"Set {name}") if textureProp.menu: tex = textureProp.tex - prop_input_name = inputGroup.column() + width, height = textureProp.size prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(textureProp, "tex_set", text="Set Texture") - texIndex = name[-1] - - prop_input.prop(textureProp, "use_tex_reference") - if textureProp.use_tex_reference: - prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") - prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") - if textureProp.tex_format[:2] == "CI": - if textureProp.flipbook is None or not textureProp.flipbook.enable: - prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") - prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") - + flipbook = textureProp.flipbook is not None and textureProp.flipbook.enable + row = prop_input.row() + row.prop(textureProp, "load_tex") + if textureProp.load_tex: + row.prop(textureProp, "use_tex_reference") + if textureProp.use_tex_reference: + prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") else: + prop_split(prop_input, textureProp, "tex_index", "Texture Index") + if not flipbook or textureProp.has_texture: prop_input.template_ID( - textureProp, "tex", new="image.new", open="image.open", unlink="image.tex" + texIndex + "_unlink" + textureProp, + "tex", + new="image.new", + open="image.open", + text=None if textureProp.has_texture else "Preview Only", ) - prop_input.enabled = textureProp.tex_set - - if tex is not None: - prop_input.label(text="Size: " + str(tex.size[0]) + " x " + str(tex.size[1])) - - if textureProp.use_tex_reference: - width, height = textureProp.tex_reference_size[0], textureProp.tex_reference_size[1] - elif tex is not None: - width, height = tex.size[0], tex.size[1] - else: - width = height = 0 + if textureProp.has_texture: + size = textureProp.size + prop_input.label(text=f"Size: {size[0]}x{size[1]}") + if not textureProp.has_texture: + prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") + prop_split(prop_input, textureProp, "tex_format", name="Format") if canUseLargeTextures: availTmem = 512 @@ -3110,18 +3154,48 @@ def ui_image( msg.label(text="Recommend using Create Large Texture Mesh tool.") else: tmemUsageUI(prop_input, textureProp) - - prop_split(prop_input, textureProp, "tex_format", name="Format") - if textureProp.tex_format[:2] == "CI": + prop_input.separator(factor=0.5) + + if textureProp.is_ci: + row = prop_input.row() + row.prop(textureProp, "load_pal") + if textureProp.load_pal: + row.prop(textureProp, "use_pal_reference") + if textureProp.load_pal: + if textureProp.use_pal_reference and textureProp.load_pal: + prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") + if textureProp.pal is None: + prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") + else: + prop_split(prop_input, textureProp, "pal_index", "Palette Index") + if not textureProp.has_texture or not textureProp.has_palette: + prop_input.template_ID(textureProp, "pal", new="image.new", open="image.open") + if textureProp.has_texture: + if textureProp.pal: + multilineLabel( + prop_input, + text="Reference pallete, the texture will be quantized and indexed\n" + "against this palette.", + icon="INFO", + ) + else: + multilineLabel( + prop_input, + text="No reference pallete set, a greyscale version of the\n" + "texture will be used as indices to the pallete", + icon="INFO", + ) prop_split(prop_input, textureProp, "ci_format", name="CI Format") if not isLarge: if width > 0 and height > 0: texelsPerWord = 64 // texBitSizeInt[textureProp.tex_format] if width % texelsPerWord != 0: - msg = prop_input.box().column() - msg.label(text=f"Suggest {textureProp.tex_format} tex be multiple ", icon="INFO") - msg.label(text=f"of {texelsPerWord} pixels wide for fast loading.") + multilineLabel( + prop_input.box(), + f"Suggest {textureProp.tex_format} tex be multiple\nof {texelsPerWord} pixels wide for fast loading.", + icon="INFO", + ) warnClampS = ( not isPowerOf2(width) and not textureProp.S.clamp @@ -3133,9 +3207,11 @@ def ui_image( and (not textureProp.autoprop or textureProp.T.mask != 0) ) if warnClampS or warnClampT: - msg = prop_input.box().column() - msg.label(text=f"Clamping required for non-power-of-2 image", icon="ERROR") - msg.label(text=f"dimensions. Enable clamp or set mask to 0.") + multilineLabel( + prop_input.box(), + "Clamping required for non-power-of-2 image\ndimensions. Enable clamp or set mask to 0.", + icon="ERROR", + ) texFieldSettings = prop_input.column() clampSettings = texFieldSettings.row() @@ -3147,7 +3223,6 @@ def ui_image( mirrorSettings.prop(textureProp.T, "mirror", text="Mirror T") prop_input.prop(textureProp, "autoprop", text="Auto Set Other Properties") - if not textureProp.autoprop: mask = prop_input.row() mask.prop(textureProp.S, "mask", text="Mask S") From 075f711d3f090ef8c4dae30f1d3407e5292e23c5 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 23 Apr 2025 15:04:43 +0100 Subject: [PATCH 03/32] UI: dithering --- fast64_internal/f3d/f3d_material.py | 61 +++++++++++++++++------------ fast64_internal/utility.py | 36 +++++++++++++++++ 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 25405532c..0aed8c64e 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -684,17 +684,12 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") prop_split(inputGroup, settings, "g_mdsft_textconv", "Texture Convert") prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") - textlut_col = inputGroup.column() tlut_mode = get_textlut_mode(dataHolder, True) if isinstance(dataHolder, F3DMaterialProperty) else None - if tlut_mode: - textlut_col.enabled = False - split = textlut_col.split(factor=0.5) - split.label(text="Texture LUT (Auto)") - box = split.box() - box.label(text={"G_TT_NONE": "None"}.get(tlut_mode, tlut_mode.lstrip("G_TT_"))) - box.scale_y = 0.5 - else: - prop_split(textlut_col, settings, "g_mdsft_textlut", "Texture LUT") + label = "" + if tlut_mode is not None: + label = tlut_mode.lstrip("G_TT_") + label = {"NONE": "None"}.get(label, label) + draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", label) prop_split(inputGroup, settings, "g_mdsft_textlod", "Texture LOD (Mipmapping)") if settings.g_mdsft_textlod == "G_TL_LOD": inputGroup.prop(settings, "num_textures_mipmapped", text="Number of Mipmaps") @@ -1260,7 +1255,6 @@ def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): multilineLabel(layout, text, icon="ERROR") def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout, context): - f3d = get_F3D_GBI() self.ui_uvCheck(layout, context) inputCol = layout.column() @@ -2262,7 +2256,7 @@ def get_tex_gen_size(tex_size: list[int | float]): return (tex_size[0] - 1) / 1024, (tex_size[1] - 1) / 1024 -def get_textlut_mode(f3d_mat: "F3DMaterialProperty", inherit_from_tex: bool = False): +def get_textlut_mode(f3d_mat: "F3DMaterialProperty", inherit_from_tex: bool = False): # TODO use_dict = all_combiner_uses(f3d_mat) textures = [f3d_mat.tex0] if use_dict["Texture 0"] and f3d_mat.tex0.tex_set else [] textures += [f3d_mat.tex1] if use_dict["Texture 1"] and f3d_mat.tex1.tex_set else [] @@ -2929,22 +2923,17 @@ class TextureProperty(PropertyGroup): name="Texture", update=update_tex_values_and_formats, ) - + auto_fmt: bpy.props.BoolProperty( + name="Auto Format", + default=True, + update=update_tex_values_and_formats, + ) tex_format: bpy.props.EnumProperty( name="Format", items=enumTexFormat, default="RGBA16", update=update_tex_values, ) - ci_format: bpy.props.EnumProperty( - name="CI Format", - items=enumCIFormat, - default="RGBA16", - update=update_tex_values, - ) - S: bpy.props.PointerProperty(type=TextureFieldProperty) - T: bpy.props.PointerProperty(type=TextureFieldProperty) - use_tex_reference: bpy.props.BoolProperty( name="Reference", default=False, @@ -2955,6 +2944,15 @@ class TextureProperty(PropertyGroup): default=True, update=update_tex_values, ) + dithering_method: bpy.props.EnumProperty( + name="Dithering Method", + items=[ + ("NONE", "None", ""), + ("RANDOM", "Random", ""), + ("DITHERED", "Dithered", ""), + ("Floyd-Steinberg", "Floyd-Steinberg", ""), + ], + ) tex_index: bpy.props.IntProperty( name="Texture Index", default=0, @@ -2974,6 +2972,12 @@ class TextureProperty(PropertyGroup): update=update_tex_values, ) + ci_format: bpy.props.EnumProperty( + name="CI Format", + items=enumCIFormat, + default="RGBA16", + update=update_tex_values, + ) use_pal_reference: bpy.props.BoolProperty( name="Reference", default=False, @@ -3008,6 +3012,9 @@ class TextureProperty(PropertyGroup): default=16, ) + S: bpy.props.PointerProperty(type=TextureFieldProperty) + T: bpy.props.PointerProperty(type=TextureFieldProperty) + menu: bpy.props.BoolProperty() tex_set: bpy.props.BoolProperty( default=True, @@ -3065,6 +3072,7 @@ def key(self): self.pal_reference_size if texSet and useRef and isCI else None, self.load_tex if texSet else None, self.load_pal if texSet and isCI else None, + self.dithering_method if texSet else None, ) @@ -3109,7 +3117,6 @@ def ui_image( if showCheckBox: row.prop(textureProp, "tex_set", text=f"Set {name}") if textureProp.menu: - tex = textureProp.tex width, height = textureProp.size prop_input = inputGroup.column() @@ -3135,7 +3142,11 @@ def ui_image( prop_input.label(text=f"Size: {size[0]}x{size[1]}") if not textureProp.has_texture: prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") - prop_split(prop_input, textureProp, "tex_format", name="Format") + prop_split(prop_input, textureProp, "dithering_method", "Dithering Method") + + fmt_row = prop_input.row() + fmt_row.prop(textureProp, "auto_fmt", text="Auto Format") + draw_forced(fmt_row, textureProp, "tex_format", textureProp.auto_fmt, "", "TODO", split=False) if canUseLargeTextures: availTmem = 512 @@ -3147,7 +3158,6 @@ def ui_image( isLarge = getTmemWordUsage(textureProp.tex_format, width, height) > availTmem else: isLarge = False - if isLarge: msg = prop_input.box().column() msg.label(text="This is a large texture.", icon="INFO") @@ -3186,6 +3196,7 @@ def ui_image( icon="INFO", ) prop_split(prop_input, textureProp, "ci_format", name="CI Format") + prop_input.separator(factor=0.5) if not isLarge: if width > 0 and height > 0: diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index e709391f1..b9ba1331f 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1310,6 +1310,42 @@ def filepath_ui_warnings( return run_and_draw_errors(layout, filepath_checks, path, empty, doesnt_exist, not_a_file, False) +def draw_forced( + layout: UILayout, + holder, + prop: str, + forced: bool, + name: Optional[str] = None, + label: Optional[str] = None, + split=True, +): + split = layout.split(factor=0.5) if split else layout.row(align=True) + left_row = split.row() + left_row.alignment = "LEFT" + right_row = split.row() + if forced or name: + left_row.label(text="" if name is None else name, icon="LOCKED" if forced else "NONE") + if not split: + right_row.alignment = "LEFT" + right_row.enabled = not forced + if forced and label is not None: + prop_size_label(right_row, text=label) + else: + right_row.prop( + holder, + prop, + text=None if label is None else "", + invert_checkbox=not getattr(holder, prop) if forced else False, + ) + + +def prop_size_label(layout: UILayout, **label_args): + box = layout.box() + box.scale_y = 0.5 + box.label(**label_args) + return box + + def toAlnum(name, exceptions=[]): if name is None or name == "": return None From 86dc202580c6d77f9511ad90ee747ea9836691db Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 24 Apr 2025 10:17:56 +0100 Subject: [PATCH 04/32] pseudo fmt ui --- fast64_internal/f3d/f3d_material.py | 253 +++++++++++++++++++--------- 1 file changed, 174 insertions(+), 79 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 0aed8c64e..498942243 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -502,7 +502,7 @@ def all_combiner_uses(f3d_mat: "F3DMaterialProperty") -> dict[str, bool]: f3d_mat, ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], ) - or f3d_mat.rdp_settings.g_mdsft_textlod == "G_TL_LOD", + or f3d_mat.uses_mipmap == "G_TL_LOD", "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"]), "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False), "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False) @@ -690,8 +690,12 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): label = tlut_mode.lstrip("G_TT_") label = {"NONE": "None"}.get(label, label) draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", label) - prop_split(inputGroup, settings, "g_mdsft_textlod", "Texture LOD (Mipmapping)") - if settings.g_mdsft_textlod == "G_TL_LOD": + is_lod, is_auto_mip = settings.g_mdsft_textlod == "G_TL_LOD", False + is_auto_mip = settings.g_mdsft_textlod == "G_TL_LOD" + if isinstance(dataHolder, F3DMaterialProperty): + is_lod, is_auto_mip = dataHolder.uses_mipmap, dataHolder.gen_auto_mips + draw_forced(inputGroup, settings, "g_mdsft_textlod", is_auto_mip, "Texture LOD", "LoD" if is_lod else "") + if is_lod and not is_auto_mip: inputGroup.prop(settings, "num_textures_mipmapped", text="Number of Mipmaps") if settings.num_textures_mipmapped > 2: box = inputGroup.box() @@ -1254,7 +1258,62 @@ def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): text += f"\n{tlut.lstrip('G_TT_')}: Texture{'s' if len(textures) > 1 else ''} {', '.join(textures)}" multilineLabel(layout, text, icon="ERROR") - def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout, context): + def draw_textures( + self, f3d_mat: "F3DMaterialProperty", material: bpy.types.Material, layout: UILayout, is_simple: bool + ): + textures = f3d_mat.set_textures.items() if is_simple else f3d_mat.used_textures.items() + if textures: + col = layout.box().column() + col.label(text="Textures", icon="IMAGE_DATA") + else: + col = layout.column() + if len(textures) > 0: + pseudo_split = col.split(factor=0.5) + pseudo_split.prop(f3d_mat, "gen_pseudo_format") + if f3d_mat.gen_pseudo_format: + pseudo_split.prop(f3d_mat, "pseudo_format_internal", text="") + if f3d_mat.pseudo_fmt_can_mip: + mipmaps_split = col.split(factor=0.5) + draw_forced(mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, "", None, False) + if f3d_mat.gen_auto_mips: + mipmaps_split.prop(f3d_mat, "auto_mipmaps", text="") + elif f3d_mat.uses_mipmap: + multilineLabel( + col, + "WARNING: This pseudo-format does\nnot support mipmaps (see tooltip), yet\nLOD mode is enabled?", + "ERROR", + ) + if f3d_mat.uses_mipmap and not f3d_mat.is_multi_tex: + multilineLabel( + col, + "WARNING: Without linear interpolation\nbetween the two texture samplers,\nmipmaps will switch between tiles per\npixel.", + "ERROR", + ) + if len(textures) > 1: + col.prop(f3d_mat, "uv_basis", text="UV Basis") + self.ui_large(f3d_mat, col) + self.ui_scale(f3d_mat, col) + self.draw_ci_warnings( + col, f3d_mat + ) # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that + if f3d_mat.gen_auto_mips or f3d_mat.gen_pseudo_format: + ui_image( + f3d_mat.use_large_textures, + col, + material, + f3d_mat.all_textures[0], + "Base Texture", + False, + always_load=True, + forced_fmt=f3d_mat.gen_pseudo_format, + ) + return + for i, tex in textures: + if i == 0: + col.separator(factor=0.5) + ui_image(f3d_mat.use_large_textures, col, material, tex, f"Texture {i}", not is_simple) + + def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout: UILayout, context): self.ui_uvCheck(layout, context) inputCol = layout.column() @@ -1262,16 +1321,7 @@ def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout, context): self.checkDrawLayersWarnings(f3dMat, useDict, layout) - self.draw_ci_warnings(inputCol, f3dMat) - for i, tex in f3dMat.set_textures.items(): - ui_image(f3dMat.use_large_textures, inputCol, material, tex, f"Texture {i}", False) - - if len(f3dMat.set_textures) > 1: - inputCol.prop(f3dMat, "uv_basis", text="UV Basis") - - if useDict["Texture"]: - self.ui_large(f3dMat, inputCol) - self.ui_scale(f3dMat, inputCol) + self.draw_textures(f3dMat, material, inputCol, True) if useDict["Primitive"] and f3dMat.set_prim: self.ui_prim(material, inputCol, "set_prim", f3dMat.set_prim, False) @@ -1351,16 +1401,7 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl inputCol = layout.column() - self.draw_ci_warnings(inputCol, f3dMat) - for i, tex in f3dMat.used_textures.items(): - ui_image(f3dMat.use_large_textures, inputCol, material, tex, f"Texture {i}", True) - - if len(f3dMat.set_textures) > 1: - inputCol.prop(f3dMat, "uv_basis", text="UV Basis") - - if useDict["Texture"]: - self.ui_large(f3dMat, inputCol) - self.ui_scale(f3dMat, inputCol) + self.draw_textures(f3dMat, material, inputCol, False) if useDict["Primitive"]: self.ui_prim(material, inputCol, "set_prim", f3dMat.set_prim, True) @@ -3109,51 +3150,58 @@ def ui_image( name: str, showCheckBox: bool, hide_lowhigh=False, + always_load=False, + forced_fmt=False, ): - inputGroup = layout.box().column() + inputGroup = layout.column() row = inputGroup.row() row.prop(textureProp, "menu", text="", icon="TRIA_DOWN" if textureProp.menu else "TRIA_RIGHT", emboss=False) if showCheckBox: row.prop(textureProp, "tex_set", text=f"Set {name}") + else: + row.label(text=name) if textureProp.menu: width, height = textureProp.size prop_input = inputGroup.column() flipbook = textureProp.flipbook is not None and textureProp.flipbook.enable row = prop_input.row() - row.prop(textureProp, "load_tex") - if textureProp.load_tex: - row.prop(textureProp, "use_tex_reference") - if textureProp.use_tex_reference: - prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") - else: - prop_split(prop_input, textureProp, "tex_index", "Texture Index") - if not flipbook or textureProp.has_texture: + has_texture = textureProp.has_texture or always_load + if not always_load: + row.prop(textureProp, "load_tex") + if textureProp.load_tex: + row.prop(textureProp, "use_tex_reference") + if textureProp.use_tex_reference: + prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") + else: + prop_split(prop_input, textureProp, "tex_index", "Texture Index") + if not flipbook or has_texture or always_load: prop_input.template_ID( textureProp, "tex", new="image.new", open="image.open", - text=None if textureProp.has_texture else "Preview Only", + text=None if has_texture else "Preview Only", ) - if textureProp.has_texture: + if has_texture: size = textureProp.size prop_input.label(text=f"Size: {size[0]}x{size[1]}") if not textureProp.has_texture: prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") prop_split(prop_input, textureProp, "dithering_method", "Dithering Method") - fmt_row = prop_input.row() - fmt_row.prop(textureProp, "auto_fmt", text="Auto Format") - draw_forced(fmt_row, textureProp, "tex_format", textureProp.auto_fmt, "", "TODO", split=False) + if not forced_fmt: + fmt_row = prop_input.row() + fmt_row.prop(textureProp, "auto_fmt", text="Auto Format") + draw_forced(fmt_row, textureProp, "tex_format", textureProp.auto_fmt, "", "TODO", split=False) + # TODO: auto fmt/pseudo fmt proper word usage if canUseLargeTextures: availTmem = 512 if textureProp.tex_format[:2] == "CI": availTmem /= 2 - useDict = all_combiner_uses(material.f3d_mat) - if useDict["Texture 0"] and useDict["Texture 1"]: + if material.f3d_mat.is_multi_tex: availTmem /= 2 isLarge = getTmemWordUsage(textureProp.tex_format, width, height) > availTmem else: @@ -3167,36 +3215,39 @@ def ui_image( prop_input.separator(factor=0.5) if textureProp.is_ci: - row = prop_input.row() - row.prop(textureProp, "load_pal") - if textureProp.load_pal: - row.prop(textureProp, "use_pal_reference") - if textureProp.load_pal: - if textureProp.use_pal_reference and textureProp.load_pal: - prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") - if textureProp.pal is None: - prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") - else: - prop_split(prop_input, textureProp, "pal_index", "Palette Index") - if not textureProp.has_texture or not textureProp.has_palette: - prop_input.template_ID(textureProp, "pal", new="image.new", open="image.open") - if textureProp.has_texture: - if textureProp.pal: - multilineLabel( - prop_input, - text="Reference pallete, the texture will be quantized and indexed\n" - "against this palette.", - icon="INFO", - ) - else: - multilineLabel( - prop_input, - text="No reference pallete set, a greyscale version of the\n" - "texture will be used as indices to the pallete", - icon="INFO", - ) - prop_split(prop_input, textureProp, "ci_format", name="CI Format") - prop_input.separator(factor=0.5) + if not always_load: + row = prop_input.row() + row.prop(textureProp, "load_pal") + if textureProp.load_pal: + row.prop(textureProp, "use_pal_reference") + if textureProp.load_pal: + if textureProp.use_pal_reference and textureProp.load_pal: + prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") + if textureProp.pal is None: + prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") + else: + prop_split(prop_input, textureProp, "pal_index", "Palette Index") + if not textureProp.has_texture or not textureProp.has_palette: + prop_input.template_ID(textureProp, "pal", new="image.new", open="image.open") + if textureProp.has_texture: + if textureProp.pal: + multilineLabel( + prop_input, + text="Reference pallete, the texture will be quantized and indexed\n" + "against this palette.", + icon="INFO", + ) + else: + multilineLabel( + prop_input, + text="No reference pallete set, a greyscale version of the\n" + "texture will be used as indices to the pallete", + icon="INFO", + ) + if not forced_fmt: + prop_split(prop_input, textureProp, "ci_format", name="CI Format") + if not always_load: + prop_input.separator(factor=0.5) if not isLarge: if width > 0 and height > 0: @@ -4435,19 +4486,36 @@ class F3DMaterialProperty(PropertyGroup): combiner1: bpy.props.PointerProperty(type=CombinerProperty) combiner2: bpy.props.PointerProperty(type=CombinerProperty) - # Texture animation + # Texture animation TODO: move this OUT menu_procAnim: bpy.props.BoolProperty() UVanim0: bpy.props.PointerProperty(type=ProcAnimVectorProperty) # material textures - tex_scale: bpy.props.FloatVectorProperty( - min=0, - max=1, - size=2, - default=(1, 1), - step=1, + gen_pseudo_format: bpy.props.BoolProperty(name="Pseudo Formats", update=update_tex_values) + pseudo_format_internal: bpy.props.EnumProperty( + name="Pseudo Formats", + items=[ + ( + "IHQ", + "IHQ", + "A pseudo format derived from RGBA16 and I4 interpolation.\n" + "By utilizing DETAIL LoD mode, we can achieve a LOD_FRAC that never goes past 0.5,\n" + "meaning even up close tex0 (the detail i4) will still be blended half way with the color.\n" + "This pseudo format fully supports (and requires) mipmaps.", + ), + ( + "SHQ", + "SHQ", + "A pseudo format derived from RGBA16 and I4 subtraction.\n" + "Subtraction can lead to much more accurate colors, but since\n" + "we need both tex0 and tex1 to be consistent this cannot be used with mipmaps.", + ), + ], update=update_tex_values, ) + gen_auto_mips_internal: bpy.props.BoolProperty(name="Auto Mipmaps", update=update_tex_values) + auto_mipmaps: bpy.props.EnumProperty(name="Auto Mipmaps", items=[("BOX", "Box", "Box")], update=update_tex_values) + tex_scale: bpy.props.FloatVectorProperty(min=0, max=1, size=2, default=(1, 1), step=1, update=update_tex_values) tex0: bpy.props.PointerProperty(type=TextureProperty, name="tex0") tex1: bpy.props.PointerProperty(type=TextureProperty, name="tex1") tex2: bpy.props.PointerProperty(type=TextureProperty, name="tex2") @@ -4615,7 +4683,7 @@ class F3DMaterialProperty(PropertyGroup): update=update_light_properties, ) set_ambient_from_light: bpy.props.BoolProperty( - "Automatic Ambient Color", default=True, update=update_light_properties + name="Automatic Ambient Color", default=True, update=update_light_properties ) ambient_light_color: bpy.props.FloatVectorProperty( name="Ambient Light Color", @@ -4739,6 +4807,10 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) + @property + def uses_mipmap(self) -> bool: + return self.rdp_settings.g_mdsft_textlod == "G_TL_LOD" or self.gen_auto_mips + @property def all_textures(self) -> list[TextureProperty]: return tuple(getattr(self, f"tex{i}") for i in range(8)) @@ -4746,7 +4818,9 @@ def all_textures(self) -> list[TextureProperty]: @property def used_textures(self) -> dict[int, TextureProperty]: self.rdp_settings: RDPSettings - if self.rdp_settings.g_mdsft_textlod == "G_TL_LOD": + if self.gen_pseudo_format or self.gen_auto_mips: + return {0: self.all_textures[0]} + if self.uses_mipmap: return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} use_dict = all_combiner_uses(self) return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} @@ -4755,6 +4829,27 @@ def used_textures(self) -> dict[int, TextureProperty]: def set_textures(self): return {i: tex for i, tex in self.used_textures.items() if tex.tex_set} + @property + def pseudo_format(self): + return self.pseudo_format_internal if self.gen_pseudo_format else "NONE" + + @property + def pseudo_fmt_can_mip(self): + return self.pseudo_format in {"IHQ", "NONE"} + + @property + def forced_mipmap(self): + return self.pseudo_format in {"IHQ"} + + @property + def gen_auto_mips(self) -> bool: + return self.pseudo_fmt_can_mip and (self.gen_auto_mips_internal or self.forced_mipmap) + + @property + def is_multi_tex(self): + use_dict = all_combiner_uses(self) + return use_dict["Texture 0"] and use_dict["Texture 1"] + def key(self) -> F3DMaterialHash: useDefaultLighting = self.set_lights and self.use_default_lighting return ( From 69a81d93c2df2924a0700ca9416cc6c826a0f766 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 24 Apr 2025 16:48:51 +0100 Subject: [PATCH 05/32] show forced for more props --- fast64_internal/f3d/f3d_enums.py | 2 +- fast64_internal/f3d/f3d_material.py | 306 +++++++++++++++------------- fast64_internal/f3d/f3d_writer.py | 10 +- fast64_internal/utility.py | 25 +-- 4 files changed, 180 insertions(+), 163 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 7746de1b0..33eca0f2a 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -343,7 +343,7 @@ ("CI8", "Color Index 8-bit", "Color Index 8-bit"), ("RGBA16", "RGBA 16-bit", "RGBA 16-bit"), ("RGBA32", "RGBA 32-bit", "RGBA 32-bit"), - # ('YUV16','YUV 16-bit', 'YUV 16-bit'), + ("YUV16", "YUV 16-bit", "YUV 16-bit"), ] enumCIFormat = [ diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 498942243..34612b584 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -502,14 +502,14 @@ def all_combiner_uses(f3d_mat: "F3DMaterialProperty") -> dict[str, bool]: f3d_mat, ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], ) - or f3d_mat.uses_mipmap == "G_TL_LOD", + or f3d_mat.uses_mipmap, "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"]), "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False), "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False) or combiner_uses(f3d_mat, ["SHADE_ALPHA"], checkAlpha=False), "Key": combiner_uses(f3d_mat, ["CENTER", "SCALE"]), "LOD Fraction": combiner_uses(f3d_mat, ["LOD_FRACTION"]), - "Convert": combiner_uses(f3d_mat, ["K4", "K5"]), + "Convert": combiner_uses(f3d_mat, ["K4", "K5"]), # TODO: check for yuv textures } return useDict @@ -684,27 +684,23 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") prop_split(inputGroup, settings, "g_mdsft_textconv", "Texture Convert") prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") - tlut_mode = get_textlut_mode(dataHolder, True) if isinstance(dataHolder, F3DMaterialProperty) else None - label = "" - if tlut_mode is not None: - label = tlut_mode.lstrip("G_TT_") - label = {"NONE": "None"}.get(label, label) - draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", label) - is_lod, is_auto_mip = settings.g_mdsft_textlod == "G_TL_LOD", False - is_auto_mip = settings.g_mdsft_textlod == "G_TL_LOD" + tlut_mode = None + tex_lod, tex_detail, mip_count = None, None, None if isinstance(dataHolder, F3DMaterialProperty): - is_lod, is_auto_mip = dataHolder.uses_mipmap, dataHolder.gen_auto_mips - draw_forced(inputGroup, settings, "g_mdsft_textlod", is_auto_mip, "Texture LOD", "LoD" if is_lod else "") - if is_lod and not is_auto_mip: - inputGroup.prop(settings, "num_textures_mipmapped", text="Number of Mipmaps") - if settings.num_textures_mipmapped > 2: - box = inputGroup.box() - box.alert = True - box.label( - text="WARNING: Fast64 does not support setting more than two textures.", icon="LIBRARY_DATA_BROKEN" - ) - box.label(text="Additional texture tiles will need to be set up manually.") - prop_split(inputGroup, settings, "g_mdsft_textdetail", "Texture Detail") + tlut_mode = dataHolder.tlut_mode + # TODO: proper auto mip count once we start using tex manager for preview and UI + tex_lod, tex_detail, mip_count = ( + dataHolder.tex_lod, + dataHolder.tex_detail, + 2 if dataHolder.gen_auto_mips else None, + ) + draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", tlut_mode) + draw_forced(inputGroup, settings, "g_mdsft_textlod", tex_lod is not None, "Texture LOD", tex_lod) + if settings.g_mdsft_textlod == "G_TL_LOD" or tex_lod: + draw_forced( + inputGroup, settings, "num_textures_mipmapped", mip_count is not None, "Number of Mipmaps", mip_count + ) + draw_forced(inputGroup, settings, "g_mdsft_textdetail", tex_detail is not None, "Texture Detail", tex_detail) prop_split(inputGroup, settings, "g_mdsft_textpersp", "Texture Perspective Correction") prop_split(inputGroup, settings, "g_mdsft_cycletype", "Cycle Type") prop_split(inputGroup, settings, "g_mdsft_pipeline", "Pipeline Span Buffer Coherency") @@ -750,10 +746,10 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input.enabled = dataHolder.set_blend -def tmemUsageUI(layout, textureProp: "TextureProperty"): - tex_size = textureProp.size - tmemUsage = getTmemWordUsage(textureProp.tex_format, tex_size[0], tex_size[1]) * 8 - tmemMax = getTmemMax(textureProp.tex_format) +def tmemUsageUI(layout, tex_prop: "TextureProperty"): + tex_size = tex_prop.size + tmemUsage = getTmemWordUsage(tex_prop.tex_format, tex_size[0], tex_size[1]) * 8 + tmemMax = getTmemMax(tex_prop.tex_format) layout.label(text="TMEM Usage: " + str(tmemUsage) + " / " + str(tmemMax) + " bytes") if tmemUsage > tmemMax: multilineLabel( @@ -798,11 +794,10 @@ def ui_prop_non_node(self, material, layout, label, name, setName, setProp): return inputGroup def ui_large(self, material, layout): - layout.prop(material, "use_large_textures") + split = layout.row().split(factor=0.5) + split.prop(material, "use_large_textures") if material.use_large_textures: - inputGroup = layout.row().split(factor=0.5) - inputGroup.label(text="Large texture edges:") - inputGroup.prop(material, "large_edges", text="") + split.prop(material, "large_edges", text="") def ui_scale(self, material, layout): inputGroup = layout.row().split(factor=0.5) @@ -1245,36 +1240,28 @@ def checkDrawLayersWarnings(self, f3dMat: "F3DMaterialProperty", useDict: Dict[s noticeBox.label(text='They must be called "Col" and "Alpha".', icon="IMAGE_ALPHA") def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): - tlut_modes = set(tex.tlut_mode for tex in f3d_mat.set_textures.values()) - if len(tlut_modes) <= 1: - return - if "G_TT_NONE" in tlut_modes: - multilineLabel(layout, "Can't mix CI and non-CI textures.", icon="ERROR") - return - else: - text = "CI textures must use the same CI format." - for tlut in tlut_modes: - textures = [str(i) for i, tex in f3d_mat.set_textures.items() if tex.tlut_mode == tlut] - text += f"\n{tlut.lstrip('G_TT_')}: Texture{'s' if len(textures) > 1 else ''} {', '.join(textures)}" - multilineLabel(layout, text, icon="ERROR") + try: + _ = f3d_mat.get_tlut_mode() + except Exception as exc: + multilineLabel(layout.box(), str(exc), icon="ERROR") def draw_textures( self, f3d_mat: "F3DMaterialProperty", material: bpy.types.Material, layout: UILayout, is_simple: bool ): - textures = f3d_mat.set_textures.items() if is_simple else f3d_mat.used_textures.items() - if textures: - col = layout.box().column() - col.label(text="Textures", icon="IMAGE_DATA") - else: - col = layout.column() + textures = f3d_mat.set_textures if is_simple else f3d_mat.used_textures + col = layout.column() if len(textures) > 0: + col.label(text="Textures", icon="IMAGE_DATA") + pseudo_split = col.split(factor=0.5) pseudo_split.prop(f3d_mat, "gen_pseudo_format") if f3d_mat.gen_pseudo_format: pseudo_split.prop(f3d_mat, "pseudo_format_internal", text="") if f3d_mat.pseudo_fmt_can_mip: mipmaps_split = col.split(factor=0.5) - draw_forced(mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, "", None, False) + draw_forced( + mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, name=None, split=False + ) if f3d_mat.gen_auto_mips: mipmaps_split.prop(f3d_mat, "auto_mipmaps", text="") elif f3d_mat.uses_mipmap: @@ -1289,29 +1276,33 @@ def draw_textures( "WARNING: Without linear interpolation\nbetween the two texture samplers,\nmipmaps will switch between tiles per\npixel.", "ERROR", ) - if len(textures) > 1: - col.prop(f3d_mat, "uv_basis", text="UV Basis") self.ui_large(f3d_mat, col) self.ui_scale(f3d_mat, col) - self.draw_ci_warnings( - col, f3d_mat - ) # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that + if len(textures) > 1: + col.prop(f3d_mat, "uv_basis", text="UV Basis") + # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that + self.draw_ci_warnings(col, f3d_mat) + col.separator(factor=1.0) if f3d_mat.gen_auto_mips or f3d_mat.gen_pseudo_format: ui_image( f3d_mat.use_large_textures, + f3d_mat.is_multi_tex, col, - material, f3d_mat.all_textures[0], "Base Texture", False, always_load=True, forced_fmt=f3d_mat.gen_pseudo_format, ) + col.separator(factor=1.0) return - for i, tex in textures: - if i == 0: - col.separator(factor=0.5) - ui_image(f3d_mat.use_large_textures, col, material, tex, f"Texture {i}", not is_simple) + + for i, (tex_index, tex) in enumerate(textures.items()): + if tex.menu and i > 0: + col.separator(factor=1.0) + ui_image(f3d_mat.use_large_textures, f3d_mat.is_multi_tex, col, tex, f"Texture {tex_index}", not is_simple) + if tex.menu or i == len(textures) - 1: + col.separator(factor=1.0) def draw_simple(self, f3dMat: "F3DMaterialProperty", material, layout: UILayout, context): self.ui_uvCheck(layout, context) @@ -2297,16 +2288,6 @@ def get_tex_gen_size(tex_size: list[int | float]): return (tex_size[0] - 1) / 1024, (tex_size[1] - 1) / 1024 -def get_textlut_mode(f3d_mat: "F3DMaterialProperty", inherit_from_tex: bool = False): # TODO - use_dict = all_combiner_uses(f3d_mat) - textures = [f3d_mat.tex0] if use_dict["Texture 0"] and f3d_mat.tex0.tex_set else [] - textures += [f3d_mat.tex1] if use_dict["Texture 1"] and f3d_mat.tex1.tex_set else [] - tlut_modes = [tex.tlut_mode for tex in textures] - if tlut_modes and tlut_modes[0] == tlut_modes[-1]: - return tlut_modes[0] - return None if inherit_from_tex else f3d_mat.rdp_settings.g_mdsft_textlut - - def update_tex_values_manual(material: Material, context, prop_path=None): f3dMat: "F3DMaterialProperty" = material.f3d_mat nodes = material.node_tree.nodes @@ -2314,7 +2295,6 @@ def update_tex_values_manual(material: Material, context, prop_path=None): texture_inputs: NodeInputs = texture_settings.inputs useDict = all_combiner_uses(f3dMat) - f3dMat.rdp_settings.g_mdsft_textlut = get_textlut_mode(f3dMat) if f3dMat.uv_basis == "": f3dMat.uv_basis = str(max(f3dMat.set_textures.keys()) if f3dMat.set_textures else -1) @@ -3068,11 +3048,16 @@ class TextureProperty(PropertyGroup): ) tile_scroll: bpy.props.PointerProperty(type=SetTileSizeScrollProperty) + tex_format: str + @property def is_ci(self): - self.tex_format: str return self.tex_format.startswith("CI") + @property + def is_yuv(self): + return self.tex_format in {"YUV16"} + @property def tlut_mode(self): return f"G_TT_{self.ci_format if self.is_ci else 'NONE'}" @@ -3094,7 +3079,7 @@ def size(self) -> tuple[int]: def key(self): texSet = self.tex_set - isCI = self.tex_format == "CI8" or self.tex_format == "CI4" + isCI = self.is_ci useRef = self.use_tex_reference return ( self.tex_set, @@ -3144,11 +3129,11 @@ def update_combiner_connections_and_preset(self, context: Context): def ui_image( canUseLargeTextures: bool, + is_multi_tex: Material, layout: UILayout, - material: Material, - textureProp: TextureProperty, + tex_prop: TextureProperty, name: str, - showCheckBox: bool, + show_toggle: bool, hide_lowhigh=False, always_load=False, forced_fmt=False, @@ -3156,54 +3141,54 @@ def ui_image( inputGroup = layout.column() row = inputGroup.row() - row.prop(textureProp, "menu", text="", icon="TRIA_DOWN" if textureProp.menu else "TRIA_RIGHT", emboss=False) - if showCheckBox: - row.prop(textureProp, "tex_set", text=f"Set {name}") + row.prop(tex_prop, "menu", text="", icon="TRIA_DOWN" if tex_prop.menu else "TRIA_RIGHT", emboss=False) + if show_toggle: + row.prop(tex_prop, "tex_set", text=f"Set {name}") else: row.label(text=name) - if textureProp.menu: - width, height = textureProp.size + if tex_prop.menu: + width, height = tex_prop.size prop_input = inputGroup.column() - flipbook = textureProp.flipbook is not None and textureProp.flipbook.enable + flipbook = tex_prop.flipbook is not None and tex_prop.flipbook.enable row = prop_input.row() - has_texture = textureProp.has_texture or always_load + has_texture = tex_prop.has_texture or always_load if not always_load: - row.prop(textureProp, "load_tex") - if textureProp.load_tex: - row.prop(textureProp, "use_tex_reference") - if textureProp.use_tex_reference: - prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") + row.prop(tex_prop, "load_tex") + if tex_prop.load_tex: + row.prop(tex_prop, "use_tex_reference") + if tex_prop.use_tex_reference: + prop_split(prop_input, tex_prop, "tex_reference", "Texture Reference") else: - prop_split(prop_input, textureProp, "tex_index", "Texture Index") + prop_split(prop_input, tex_prop, "tex_index", "Texture Index") if not flipbook or has_texture or always_load: prop_input.template_ID( - textureProp, + tex_prop, "tex", new="image.new", open="image.open", text=None if has_texture else "Preview Only", ) if has_texture: - size = textureProp.size + size = tex_prop.size prop_input.label(text=f"Size: {size[0]}x{size[1]}") - if not textureProp.has_texture: - prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") - prop_split(prop_input, textureProp, "dithering_method", "Dithering Method") + if not tex_prop.has_texture: + prop_split(prop_input, tex_prop, "tex_reference_size", "Texture Size") + prop_split(prop_input, tex_prop, "dithering_method", "Dithering Method") if not forced_fmt: fmt_row = prop_input.row() - fmt_row.prop(textureProp, "auto_fmt", text="Auto Format") - draw_forced(fmt_row, textureProp, "tex_format", textureProp.auto_fmt, "", "TODO", split=False) + fmt_row.prop(tex_prop, "auto_fmt", text="Auto Format") + draw_forced(fmt_row, tex_prop, "tex_format", tex_prop.auto_fmt, "", "TODO", split=False) # TODO: auto fmt/pseudo fmt proper word usage - if canUseLargeTextures: + if canUseLargeTextures: # TODO: rework how this works, we want multi texture large textures to be a thing availTmem = 512 - if textureProp.tex_format[:2] == "CI": + if tex_prop.tex_format[:2] == "CI": availTmem /= 2 - if material.f3d_mat.is_multi_tex: + if is_multi_tex: availTmem /= 2 - isLarge = getTmemWordUsage(textureProp.tex_format, width, height) > availTmem + isLarge = getTmemWordUsage(tex_prop.tex_format, width, height) > availTmem else: isLarge = False if isLarge: @@ -3211,26 +3196,26 @@ def ui_image( msg.label(text="This is a large texture.", icon="INFO") msg.label(text="Recommend using Create Large Texture Mesh tool.") else: - tmemUsageUI(prop_input, textureProp) + tmemUsageUI(prop_input, tex_prop) prop_input.separator(factor=0.5) - if textureProp.is_ci: + if tex_prop.is_ci: if not always_load: row = prop_input.row() - row.prop(textureProp, "load_pal") - if textureProp.load_pal: - row.prop(textureProp, "use_pal_reference") - if textureProp.load_pal: - if textureProp.use_pal_reference and textureProp.load_pal: - prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") - if textureProp.pal is None: - prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") + row.prop(tex_prop, "load_pal") + if tex_prop.load_pal: + row.prop(tex_prop, "use_pal_reference") + if tex_prop.load_pal: + if tex_prop.use_pal_reference and tex_prop.load_pal: + prop_split(prop_input, tex_prop, "pal_reference", "Palette Reference") + if tex_prop.pal is None: + prop_split(prop_input, tex_prop, "pal_reference_size", "Palette Size") else: - prop_split(prop_input, textureProp, "pal_index", "Palette Index") - if not textureProp.has_texture or not textureProp.has_palette: - prop_input.template_ID(textureProp, "pal", new="image.new", open="image.open") - if textureProp.has_texture: - if textureProp.pal: + prop_split(prop_input, tex_prop, "pal_index", "Palette Index") + if not tex_prop.has_texture or not tex_prop.has_palette: + prop_input.template_ID(tex_prop, "pal", new="image.new", open="image.open") + if tex_prop.has_texture: + if tex_prop.pal: multilineLabel( prop_input, text="Reference pallete, the texture will be quantized and indexed\n" @@ -3245,28 +3230,24 @@ def ui_image( icon="INFO", ) if not forced_fmt: - prop_split(prop_input, textureProp, "ci_format", name="CI Format") + prop_split(prop_input, tex_prop, "ci_format", name="CI Format") if not always_load: prop_input.separator(factor=0.5) if not isLarge: if width > 0 and height > 0: - texelsPerWord = 64 // texBitSizeInt[textureProp.tex_format] + texelsPerWord = 64 // texBitSizeInt[tex_prop.tex_format] if width % texelsPerWord != 0: multilineLabel( prop_input.box(), - f"Suggest {textureProp.tex_format} tex be multiple\nof {texelsPerWord} pixels wide for fast loading.", + f"Suggest {tex_prop.tex_format} tex be multiple\nof {texelsPerWord} pixels wide for fast loading.", icon="INFO", ) warnClampS = ( - not isPowerOf2(width) - and not textureProp.S.clamp - and (not textureProp.autoprop or textureProp.S.mask != 0) + not isPowerOf2(width) and not tex_prop.S.clamp and (not tex_prop.autoprop or tex_prop.S.mask != 0) ) warnClampT = ( - not isPowerOf2(height) - and not textureProp.T.clamp - and (not textureProp.autoprop or textureProp.T.mask != 0) + not isPowerOf2(height) and not tex_prop.T.clamp and (not tex_prop.autoprop or tex_prop.T.mask != 0) ) if warnClampS or warnClampT: multilineLabel( @@ -3277,31 +3258,31 @@ def ui_image( texFieldSettings = prop_input.column() clampSettings = texFieldSettings.row() - clampSettings.prop(textureProp.S, "clamp", text="Clamp S") - clampSettings.prop(textureProp.T, "clamp", text="Clamp T") + clampSettings.prop(tex_prop.S, "clamp", text="Clamp S") + clampSettings.prop(tex_prop.T, "clamp", text="Clamp T") mirrorSettings = texFieldSettings.row() - mirrorSettings.prop(textureProp.S, "mirror", text="Mirror S") - mirrorSettings.prop(textureProp.T, "mirror", text="Mirror T") + mirrorSettings.prop(tex_prop.S, "mirror", text="Mirror S") + mirrorSettings.prop(tex_prop.T, "mirror", text="Mirror T") - prop_input.prop(textureProp, "autoprop", text="Auto Set Other Properties") - if not textureProp.autoprop: + prop_input.prop(tex_prop, "autoprop", text="Auto Set Other Properties") + if not tex_prop.autoprop: mask = prop_input.row() - mask.prop(textureProp.S, "mask", text="Mask S") - mask.prop(textureProp.T, "mask", text="Mask T") + mask.prop(tex_prop.S, "mask", text="Mask S") + mask.prop(tex_prop.T, "mask", text="Mask T") shift = prop_input.row() - shift.prop(textureProp.S, "shift", text="Shift S") - shift.prop(textureProp.T, "shift", text="Shift T") + shift.prop(tex_prop.S, "shift", text="Shift S") + shift.prop(tex_prop.T, "shift", text="Shift T") if hide_lowhigh: return low = prop_input.row() - low.prop(textureProp.S, "low", text="S Low") - low.prop(textureProp.T, "low", text="T Low") + low.prop(tex_prop.S, "low", text="S Low") + low.prop(tex_prop.T, "low", text="T Low") high = prop_input.row() - high.prop(textureProp.S, "high", text="S High") - high.prop(textureProp.T, "high", text="T High") + high.prop(tex_prop.S, "high", text="S High") + high.prop(tex_prop.T, "high", text="T High") class CombinerProperty(PropertyGroup): @@ -3964,7 +3945,7 @@ def other_to_dict(self): data = {} if self.clip_ratio != 1.0: data["clipRatio"] = self.clip_ratio - if self.g_mdsft_textlod == "G_TL_LOD" and self.num_textures_mipmapped != 1: + if self.g_mdsft_textlod == "G_TL_LOD" and self.num_textures_mipmapped != 1: # TODO data["mipmapCount"] = self.num_textures_mipmapped return data @@ -4807,10 +4788,6 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) - @property - def uses_mipmap(self) -> bool: - return self.rdp_settings.g_mdsft_textlod == "G_TL_LOD" or self.gen_auto_mips - @property def all_textures(self) -> list[TextureProperty]: return tuple(getattr(self, f"tex{i}") for i in range(8)) @@ -4829,6 +4806,35 @@ def used_textures(self) -> dict[int, TextureProperty]: def set_textures(self): return {i: tex for i, tex in self.used_textures.items() if tex.tex_set} + def get_tlut_mode(self, only_auto=False): + if self.pseudo_format in {"IHQ", "SHQ"}: + return "G_TT_NONE" + tlut_modes = set(tex.tlut_mode for tex in self.set_textures.values()) + if len(tlut_modes) == 1: + return list(tlut_modes)[0] + elif len(tlut_modes) == 0: + return None if only_auto else self.rdp_settings.g_mdsft_textlut + text = ( + "Can't mix CI and non-CI textures." + if "G_TT_NONE" in tlut_modes + else "CI textures must use the same CI format." + ) + for tlut in tlut_modes: + textures = [str(i) for i, tex in self.set_textures.items() if tex.tlut_mode == tlut] + text += f"\n{tlut.lstrip('G_TT_')}: Texture{'s' if len(textures) > 1 else ''} {', '.join(textures)}" + raise PluginError(text) + + @property + def tlut_mode(self): + try: + return self.get_tlut_mode(True) + except: + return None + + @property + def is_ci(self): + return self.tlut_mode or self.rdp_settings.g_mdsft_textlut in {"G_TT_RGBA16", "G_TT_IA16"} + @property def pseudo_format(self): return self.pseudo_format_internal if self.gen_pseudo_format else "NONE" @@ -4845,6 +4851,22 @@ def forced_mipmap(self): def gen_auto_mips(self) -> bool: return self.pseudo_fmt_can_mip and (self.gen_auto_mips_internal or self.forced_mipmap) + @property + def tex_lod(self) -> bool: + if self.gen_auto_mips: + return "G_TL_LOD" + return None + + @property + def uses_mipmap(self) -> bool: + return self.rdp_settings.g_mdsft_textlod == "G_TL_LOD" or self.gen_auto_mips + + @property + def tex_detail(self) -> bool: + if self.pseudo_format in {"IHQ"}: + return "G_TD_DETAIL" + return None + @property def is_multi_tex(self): use_dict = all_combiner_uses(self) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 6d776a0b3..46db12d70 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -7,13 +7,7 @@ from bpy.utils import register_class, unregister_class from .f3d_enums import * -from .f3d_material import ( - all_combiner_uses, - getMaterialScrollDimensions, - isTexturePointSampled, - get_textlut_mode, - RDPSettings, -) +from .f3d_material import all_combiner_uses, getMaterialScrollDimensions, isTexturePointSampled, RDPSettings from .f3d_texture_writer import MultitexManager, TileLoad, maybeSaveSingleLargeTextureSetup from .f3d_gbi import * from .f3d_bleed import BleedGraphics @@ -1443,7 +1437,7 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): saveOtherModeHDefinition( fMaterial, f3dMat.rdp_settings, - get_textlut_mode(f3dMat), + f3dMat.get_tlut_mode(), defaults, fModel.matWriteMethod, fModel.f3d, diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index b9ba1331f..7e0e23e9d 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1312,29 +1312,30 @@ def filepath_ui_warnings( def draw_forced( layout: UILayout, - holder, + holder: bpy.types.bpy_struct, prop: str, forced: bool, name: Optional[str] = None, - label: Optional[str] = None, + value: Optional[str] = None, split=True, ): - split = layout.split(factor=0.5) if split else layout.row(align=True) - left_row = split.row() - left_row.alignment = "LEFT" - right_row = split.row() - if forced or name: + split_row = layout.split(factor=0.5) if split else layout.row(align=True) + left_row = split_row.row() + right_row = split_row.row() + if forced or name or split: left_row.label(text="" if name is None else name, icon="LOCKED" if forced else "NONE") - if not split: - right_row.alignment = "LEFT" right_row.enabled = not forced - if forced and label is not None: - prop_size_label(right_row, text=label) + if forced and value is not None: + props = holder.bl_rna.properties[prop] + if "Enum" in props.bl_rna.name: + props: bpy.types.EnumProperty + value: str = next((item.name for item in props.enum_items if item.identifier == value), value) + prop_size_label(right_row, text=str(value)) else: right_row.prop( holder, prop, - text=None if label is None else "", + text="" if split or name is not None else None, invert_checkbox=not getattr(holder, prop) if forced else False, ) From b2215a9e1017195d914e106bc49bb33c55fcc111 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 24 Apr 2025 16:55:40 +0100 Subject: [PATCH 06/32] export fix --- fast64_internal/f3d/f3d_material.py | 12 +++++------- fast64_internal/sm64/sm64_f3d_writer.py | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 34612b584..c3fbf49d5 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3048,14 +3048,12 @@ class TextureProperty(PropertyGroup): ) tile_scroll: bpy.props.PointerProperty(type=SetTileSizeScrollProperty) - tex_format: str - @property - def is_ci(self): + def is_ci(self) -> bool: return self.tex_format.startswith("CI") @property - def is_yuv(self): + def is_yuv(self) -> bool: return self.tex_format in {"YUV16"} @property @@ -3063,15 +3061,15 @@ def tlut_mode(self): return f"G_TT_{self.ci_format if self.is_ci else 'NONE'}" @property - def has_texture(self): + def has_texture(self) -> bool: return self.load_tex and not self.use_tex_reference @property - def has_palette(self): + def has_palette(self) -> bool: return self.load_pal and self.has_texture and not self.use_pal_reference @property - def size(self) -> tuple[int]: + def size(self) -> tuple[int, int]: if self.has_texture: if self.tex is not None: return tuple(self.tex.size) diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 01fec3177..f0f929f7a 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -876,7 +876,7 @@ def draw(self, context): infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][0] + ": ") infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][1] + ".") prop_split(col, context.scene, "TexRectName", "Name") - ui_image(False, col, None, context.scene.texrect, context.scene.TexRectName, False, hide_lowhigh=True) + ui_image(False, False, col, context.scene.texrect, context.scene.TexRectName, False, hide_lowhigh=True) col.operator(ExportTexRectDraw.bl_idname) From 749782ff1bf802462305800efc5fdd967a5abc7b Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 25 Apr 2025 16:31:22 +0100 Subject: [PATCH 07/32] i hate preventing recursion so much --- fast64_internal/f3d/f3d_material.py | 233 +++++++++++++++++----------- fast64_internal/f3d/f3d_writer.py | 6 +- 2 files changed, 146 insertions(+), 93 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index c3fbf49d5..206cae91a 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -269,7 +269,7 @@ def rendermode_preset_to_advanced(material: bpy.types.Material): Set all individual controls for the rendermode from the preset rendermode. """ scene = bpy.context.scene - f3d_mat = material.f3d_mat + f3d_mat: "F3DMaterialProperty" = material.f3d_mat settings = f3d_mat.rdp_settings f3d = get_F3D_GBI() @@ -304,7 +304,7 @@ def get_with_default(preset, default): # want, then disable it, and have it still previewed that way. return getattr(f3d, preset, default) - is_two_cycle = settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + is_two_cycle = f3d_mat.cycle_type == "G_CYC_2CYCLE" if is_two_cycle: r1 = get_with_default(cycle_1, f3d.G_RM_FOG_SHADE_A) r2 = get_with_default(cycle_2, f3d.G_RM_AA_ZB_OPA_SURF2) @@ -340,17 +340,11 @@ def get_with_default(preset, default): settings.blend_b2 = f3d.blendMixDict[(r2 >> 16) & 3] -def does_blender_use_mix(settings: "RDPSettings", mix: str, default_for_no_rendermode: bool = False) -> bool: - if not settings.set_rendermode: - return default_for_no_rendermode - is_two_cycle = settings.g_mdsft_cycletype == "G_CYC_2CYCLE" - return settings.blend_b1 == mix or (is_two_cycle and settings.blend_b2 == mix) - - -def is_blender_equation_equal(settings: "RDPSettings", cycle: int, p: str, a: str, m: str, b: str) -> bool: +def is_blender_equation_equal(f3d_mat: "F3DMaterialProperty", cycle: int, p: str, a: str, m: str, b: str) -> bool: + settings = f3d_mat.rdp_settings assert cycle in {1, 2, -1} # -1 = last cycle if cycle == -1: - cycle = 2 if settings.g_mdsft_cycletype == "G_CYC_2CYCLE" else 1 + cycle = 2 if f3d_mat.cycle_type else 1 return ( getattr(settings, f"blend_p{cycle}") == p and getattr(settings, f"blend_a{cycle}") == a @@ -359,9 +353,9 @@ def is_blender_equation_equal(settings: "RDPSettings", cycle: int, p: str, a: st ) -def is_blender_doing_fog(settings: "RDPSettings") -> bool: +def is_blender_doing_fog(f3d_mat: "F3DMaterialProperty") -> bool: return is_blender_equation_equal( - settings, + f3d_mat, # If 2 cycle, fog must be in first cycle. 1, "G_BL_CLR_FOG", @@ -380,7 +374,7 @@ def get_output_method(material: bpy.types.Material) -> str: if settings.cvg_x_alpha: return "CLIP" if settings.force_bl and is_blender_equation_equal( - settings, -1, "G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_MEM", "G_BL_1MA" + material, -1, "G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_MEM", "G_BL_1MA" ): return "XLU" return "OPA" @@ -464,8 +458,11 @@ def combiner_uses( checkColor=True, checkAlpha=True, swapTexelsCycle2=True, + cycle_type: str = None, ): - is_two_cycle = f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + if cycle_type is None: + cycle_type = f3dMat.cycle_type + is_two_cycle = cycle_type == "G_CYC_2CYCLE" for i in range(1, 3): if i == 1 and not checkCycle1 or i == 2 and (not checkCycle2 or not is_two_cycle): continue @@ -482,35 +479,35 @@ def combiner_uses( return False -def combiner_uses_tex0(f3d_mat: "F3DMaterialProperty"): - return combiner_uses(f3d_mat, ["TEXEL0", "TEXEL0_ALPHA"]) +def combiner_uses_tex0(f3d_mat: "F3DMaterialProperty", cycle_type: str = None): + return combiner_uses(f3d_mat, ["TEXEL0", "TEXEL0_ALPHA"], cycle_type=cycle_type) -def combiner_uses_tex1(f3d_mat: "F3DMaterialProperty"): - return combiner_uses(f3d_mat, ["TEXEL1", "TEXEL1_ALPHA"]) +def combiner_uses_tex1(f3d_mat: "F3DMaterialProperty", cycle_type: str = None): + return combiner_uses(f3d_mat, ["TEXEL1", "TEXEL1_ALPHA"], cycle_type=cycle_type) -def all_combiner_uses(f3d_mat: "F3DMaterialProperty") -> dict[str, bool]: - use_tex0 = combiner_uses_tex0(f3d_mat) - use_tex1 = combiner_uses_tex1(f3d_mat) +def all_combiner_uses(f3d_mat: "F3DMaterialProperty", cycle_type: str = None) -> dict[str, bool]: + use_tex0 = combiner_uses_tex0(f3d_mat, cycle_type) + use_tex1 = combiner_uses_tex1(f3d_mat, cycle_type) useDict = { "Texture": use_tex0 or use_tex1, "Texture 0": use_tex0, "Texture 1": use_tex1, - "Primitive": combiner_uses( - f3d_mat, - ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], - ) + "Primitive": combiner_uses(f3d_mat, ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], cycle_type=cycle_type) or f3d_mat.uses_mipmap, - "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"]), - "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False), - "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False) - or combiner_uses(f3d_mat, ["SHADE_ALPHA"], checkAlpha=False), - "Key": combiner_uses(f3d_mat, ["CENTER", "SCALE"]), - "LOD Fraction": combiner_uses(f3d_mat, ["LOD_FRACTION"]), - "Convert": combiner_uses(f3d_mat, ["K4", "K5"]), # TODO: check for yuv textures + "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"], cycle_type=cycle_type), + "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False, cycle_type=cycle_type), + "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False, cycle_type=cycle_type) + or combiner_uses(f3d_mat, ["SHADE_ALPHA"], checkAlpha=False, cycle_type=cycle_type), + "Key": combiner_uses(f3d_mat, ["CENTER", "SCALE"], cycle_type=cycle_type), + "LOD Fraction": combiner_uses(f3d_mat, ["LOD_FRACTION"], cycle_type=cycle_type), } + useDict["Convert"] = ( + combiner_uses(f3d_mat, ["K4", "K5"], cycle_type=cycle_type) + or f3d_mat.get_tex_convert(dont_raise=True, use_dict=useDict) != "G_TC_FILT" + ) return useDict @@ -679,21 +676,22 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): icon="TRIA_DOWN" if dataHolder.menu_upper else "TRIA_RIGHT", ) if not useDropdown or dataHolder.menu_upper: - prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") - prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") - prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") - prop_split(inputGroup, settings, "g_mdsft_textconv", "Texture Convert") - prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") - tlut_mode = None - tex_lod, tex_detail, mip_count = None, None, None + tex_conv = tlut_mode = tex_lod = tex_detail = mip_count = cycle_type = None if isinstance(dataHolder, F3DMaterialProperty): - tlut_mode = dataHolder.tlut_mode # TODO: proper auto mip count once we start using tex manager for preview and UI - tex_lod, tex_detail, mip_count = ( - dataHolder.tex_lod, - dataHolder.tex_detail, + tex_conv, tlut_mode, tex_lod, tex_detail, mip_count, cycle_type = ( + dataHolder.get_tex_convert(True, dont_raise=True), + dataHolder.get_tlut_mode(True, dont_raise=True), + dataHolder.get_tex_lod(True), + dataHolder.get_tex_detail(True), 2 if dataHolder.gen_auto_mips else None, + dataHolder.get_cycle_type(True, dont_raise=True), ) + prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") + prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") + prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") + draw_forced(inputGroup, settings, "g_mdsft_textconv", tex_conv is not None, "Texture Convert", tex_conv) + prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", tlut_mode) draw_forced(inputGroup, settings, "g_mdsft_textlod", tex_lod is not None, "Texture LOD", tex_lod) if settings.g_mdsft_textlod == "G_TL_LOD" or tex_lod: @@ -702,7 +700,7 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): ) draw_forced(inputGroup, settings, "g_mdsft_textdetail", tex_detail is not None, "Texture Detail", tex_detail) prop_split(inputGroup, settings, "g_mdsft_textpersp", "Texture Perspective Correction") - prop_split(inputGroup, settings, "g_mdsft_cycletype", "Cycle Type") + draw_forced(inputGroup, settings, "g_mdsft_cycletype", cycle_type is not None, "Cycle Type", cycle_type) prop_split(inputGroup, settings, "g_mdsft_pipeline", "Pipeline Span Buffer Coherency") @@ -794,7 +792,7 @@ def ui_prop_non_node(self, material, layout, label, name, setName, setProp): return inputGroup def ui_large(self, material, layout): - split = layout.row().split(factor=0.5) + split = layout.row().split(factor=0.5) if material.use_large_textures else layout split.prop(material, "use_large_textures") if material.use_large_textures: split.prop(material, "large_edges", text="") @@ -937,8 +935,8 @@ def ui_convert(self, material, layout, showCheckBox): prop_input.enabled = material.set_k0_5 return inputGroup - def ui_lower_render_mode(self, material, layout, useDropdown): - is_two_cycle = material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + def ui_lower_render_mode(self, material: "F3DMaterialProperty", layout, useDropdown): + is_two_cycle = material.cycle_type == "G_CYC_2CYCLE" # cycle independent inputGroup = layout.column() if useDropdown: @@ -1240,10 +1238,33 @@ def checkDrawLayersWarnings(self, f3dMat: "F3DMaterialProperty", useDict: Dict[s noticeBox.label(text='They must be called "Col" and "Alpha".', icon="IMAGE_ALPHA") def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): + errors, warnings = [], [] try: _ = f3d_mat.get_tlut_mode() except Exception as exc: - multilineLabel(layout.box(), str(exc), icon="ERROR") + errors.append(str(exc)) + try: + _ = f3d_mat.get_tex_convert() + except Exception as exc: + errors.append(str(exc)) + if f3d_mat.uses_mipmap and not f3d_mat.is_multi_tex: + warnings.append( + "Without linear interpolation\nbetween the two texture samplers,\nmipmaps will switch between tiles per\npixel." + ) + if not f3d_mat.pseudo_fmt_can_mip and f3d_mat.uses_mipmap: + warnings.append( + "WARNING: This pseudo-format does\nnot support mipmaps (see tooltip), yet\nLOD mode is enabled?" + ) + tex_convert = f3d_mat.tex_convert + if tex_convert != "G_TC_FILT": + if not (combiner_uses(f3d_mat, ["K4"]) or combiner_uses(f3d_mat, ["K5"])): + warnings.append("No K4/K5 inputs used, but YUV\nconversion is enabled.") + if tex_convert == "G_TC_FILTCONV" and not combiner_uses_tex1(f3d_mat) and combiner_uses_tex0(f3d_mat): + warnings.append("Using filter and convert, but only using\nTexture 0 which does not get converted.") + if len(errors) > 0: + multilineLabel(layout.box(), "\n".join(errors), "ERROR") + if len(warnings) > 0: + multilineLabel(layout.box(), "\n".join(warnings), "INFO") def draw_textures( self, f3d_mat: "F3DMaterialProperty", material: bpy.types.Material, layout: UILayout, is_simple: bool @@ -1253,29 +1274,18 @@ def draw_textures( if len(textures) > 0: col.label(text="Textures", icon="IMAGE_DATA") - pseudo_split = col.split(factor=0.5) + pseudo_split = col.split(factor=0.5) if f3d_mat.gen_pseudo_format else col pseudo_split.prop(f3d_mat, "gen_pseudo_format") if f3d_mat.gen_pseudo_format: pseudo_split.prop(f3d_mat, "pseudo_format_internal", text="") if f3d_mat.pseudo_fmt_can_mip: - mipmaps_split = col.split(factor=0.5) + mipmaps_split = col.split(factor=0.5) if f3d_mat.gen_auto_mips else col draw_forced( mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, name=None, split=False ) if f3d_mat.gen_auto_mips: mipmaps_split.prop(f3d_mat, "auto_mipmaps", text="") - elif f3d_mat.uses_mipmap: - multilineLabel( - col, - "WARNING: This pseudo-format does\nnot support mipmaps (see tooltip), yet\nLOD mode is enabled?", - "ERROR", - ) - if f3d_mat.uses_mipmap and not f3d_mat.is_multi_tex: - multilineLabel( - col, - "WARNING: Without linear interpolation\nbetween the two texture samplers,\nmipmaps will switch between tiles per\npixel.", - "ERROR", - ) + self.ui_large(f3d_mat, col) self.ui_scale(f3d_mat, col) if len(textures) > 1: @@ -1356,7 +1366,7 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl r.label(text=f"{letter}{' Alpha' if isAlpha else ''}:") r.prop(combiner, f"{letter}{'_alpha' if isAlpha else ''}", text="") - is_two_cycle = f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + is_two_cycle = f3dMat.cycle_type == "G_CYC_2CYCLE" combinerBox = layout.box() combinerBox.prop(f3dMat, "set_combiner", text="Color Combiner (Color = (A - B) * C + D)") @@ -1433,7 +1443,7 @@ def draw(self, context): layout.label(text="This is not a Fast3D material.") return - f3dMat = material.f3d_mat + f3dMat: "F3DMaterialProperty" = material.f3d_mat settings = f3dMat.rdp_settings layout.prop(context.scene, "f3d_simple", text="Show Simplified UI") layout = layout.box() @@ -1457,7 +1467,7 @@ def draw(self, context): row.operator(AddPresetF3D.bl_idname, text="", icon="ADD") row.operator(AddPresetF3D.bl_idname, text="", icon="REMOVE").remove_active = True - if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and f3dMat.cycle_type == "G_CYC_2CYCLE": multilineLabel( layout.box(), "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" @@ -1781,7 +1791,7 @@ def update_fog_nodes(material: Material, context: Context): # rendermodes in code, so to be safe we'll enable fog. Plus we are checking # that fog is enabled in the geometry mode, so if so that's probably the intent. fogBlender.node_tree = bpy.data.node_groups[ - ("FogBlender_On" if is_blender_doing_fog(material.f3d_mat.rdp_settings) else "FogBlender_Off") + ("FogBlender_On" if is_blender_doing_fog(material.f3d_mat) else "FogBlender_Off") ] remove_first_link_if_exists(material, fogBlender.inputs["FogAmount"].links) @@ -1855,7 +1865,7 @@ def set_output_node_groups(material: Material): nodes = material.node_tree.nodes output_node = nodes["OUTPUT"] f3dMat: "F3DMaterialProperty" = material.f3d_mat - cycle = f3dMat.rdp_settings.g_mdsft_cycletype.lstrip("G_CYC_").rstrip("_CYCLE") + cycle = f3dMat.cycle_type.lstrip("G_CYC_").rstrip("_CYCLE") output_method = get_output_method(material) if bpy.app.version < (4, 2, 0) and output_method == "CLIP": output_method = "XLU" @@ -4790,27 +4800,39 @@ class F3DMaterialProperty(PropertyGroup): def all_textures(self) -> list[TextureProperty]: return tuple(getattr(self, f"tex{i}") for i in range(8)) - @property - def used_textures(self) -> dict[int, TextureProperty]: + def get_used_textures(self, use_dict: dict = None) -> dict[int, TextureProperty]: self.rdp_settings: RDPSettings if self.gen_pseudo_format or self.gen_auto_mips: return {0: self.all_textures[0]} if self.uses_mipmap: return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} - use_dict = all_combiner_uses(self) + if use_dict is None: + use_dict = all_combiner_uses(self) return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} + @property + def used_textures(self) -> dict[int, TextureProperty]: + return self.get_used_textures() + + def get_set_textures(self, use_dict: dict = None): + return {i: tex for i, tex in self.get_used_textures(use_dict).items() if tex.tex_set} + @property def set_textures(self): - return {i: tex for i, tex in self.used_textures.items() if tex.tex_set} + return self.get_set_textures() - def get_tlut_mode(self, only_auto=False): + @property + def is_multi_tex(self): + use_dict = all_combiner_uses(self) + return use_dict["Texture 0"] and use_dict["Texture 1"] + + def get_tlut_mode(self, only_auto=False, dont_raise=False): if self.pseudo_format in {"IHQ", "SHQ"}: return "G_TT_NONE" tlut_modes = set(tex.tlut_mode for tex in self.set_textures.values()) if len(tlut_modes) == 1: return list(tlut_modes)[0] - elif len(tlut_modes) == 0: + elif len(tlut_modes) == 0 or dont_raise: return None if only_auto else self.rdp_settings.g_mdsft_textlut text = ( "Can't mix CI and non-CI textures." @@ -4824,14 +4846,11 @@ def get_tlut_mode(self, only_auto=False): @property def tlut_mode(self): - try: - return self.get_tlut_mode(True) - except: - return None + return self.get_tlut_mode(dont_raise=True) @property def is_ci(self): - return self.tlut_mode or self.rdp_settings.g_mdsft_textlut in {"G_TT_RGBA16", "G_TT_IA16"} + return self.tlut_mode in {"G_TT_RGBA16", "G_TT_IA16"} @property def pseudo_format(self): @@ -4849,26 +4868,60 @@ def forced_mipmap(self): def gen_auto_mips(self) -> bool: return self.pseudo_fmt_can_mip and (self.gen_auto_mips_internal or self.forced_mipmap) - @property - def tex_lod(self) -> bool: + def get_tex_lod(self, only_auto=False) -> bool: if self.gen_auto_mips: return "G_TL_LOD" - return None + return None if only_auto else self.rdp_settings.g_mdsft_textlod @property - def uses_mipmap(self) -> bool: - return self.rdp_settings.g_mdsft_textlod == "G_TL_LOD" or self.gen_auto_mips + def tex_lod(self) -> bool: + return self.get_tex_lod(False) - @property - def tex_detail(self) -> bool: + def get_tex_detail(self, only_auto=False) -> bool: if self.pseudo_format in {"IHQ"}: return "G_TD_DETAIL" - return None + return None if only_auto else self.rdp_settings.g_mdsft_textdetail @property - def is_multi_tex(self): - use_dict = all_combiner_uses(self) - return use_dict["Texture 0"] and use_dict["Texture 1"] + def tex_detail(self) -> bool: + return self.get_tex_detail(False) + + @property + def uses_mipmap(self) -> bool: + return self.tex_lod == "G_TL_LOD" + + def get_tex_convert(self, only_auto=False, dont_raise=False, use_dict=None): + textures = self.get_set_textures(use_dict) + fmts: set[str] = set(tex.tex_format for tex in textures.values()) + has_yuv = "YUV16" in fmts + if self.pseudo_format in {"IHQ", "SHQ"} or (not has_yuv and fmts): + return "G_TC_FILT" + if len(fmts) == 1: + if self.rdp_settings.g_mdsft_text_filt == "G_TF_POINT": + return "G_TC_CONV" + return "G_TC_FILTCONV" + elif not fmts or dont_raise: + return None if only_auto else self.rdp_settings.g_mdsft_textconv + text = "Can't mix YUV and non-YUV textures." + for fmt in fmts: + fmt_textures = [str(i) for i, tex in textures.items() if tex.tex_format == fmt] + text += f"\n{fmt.lstrip('G_TT_')}: Texture{'s' if len(fmt_textures) > 1 else ''} {', '.join(fmt_textures)}" + raise PluginError(text) + + @property + def tex_convert(self): + return self.get_tex_convert(dont_raise=True) + + def get_cycle_type(self, only_auto=False, dont_raise=False): + cur_cycle_type = self.rdp_settings.g_mdsft_cycletype + use_dict = all_combiner_uses(self, cur_cycle_type) + if self.uses_mipmap or self.get_tex_convert(dont_raise=dont_raise, use_dict=use_dict) == "G_TC_FILTCONV": + return "G_CYC_2CYCLE" + return None if only_auto else cur_cycle_type + + @property + def cycle_type(self): + return self.get_cycle_type(False, dont_raise=True) def key(self) -> F3DMaterialHash: useDefaultLighting = self.set_lights and self.use_default_lighting diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 46db12d70..e1c16a54a 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1067,7 +1067,7 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional ccSettings.append(getattr(f3dMat.combiner1, prop)) ccSettings.extend(["1", "SHADE"] if darker else ["SHADE", "0"]) ccSettings.extend([cel.cutoutSource, "0"]) - if f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + if f3dMat.cycle_type == "G_CYC_2CYCLE": for prop in ["A", "B", "C", "D", "A_alpha", "B_alpha", "C_alpha", "D_alpha"]: ccSettings.append(getattr(f3dMat.combiner2, prop)) else: @@ -1667,7 +1667,7 @@ def saveOtherModeHDefinition(fMaterial, settings, tlut, defaults, matWriteMethod raise PluginError("Unhandled material write method: " + str(matWriteMethod)) -def saveOtherModeHDefinitionAll(fMaterial, settings, tlut, defaults, f3d): +def saveOtherModeHDefinitionAll(fMaterial, settings, tlut, defaults, f3d): # TODO cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - f3d.F3D_OLD_GBI, []) cmd.flagList.append(settings.g_mdsft_alpha_dither) cmd.flagList.append(settings.g_mdsft_rgb_dither) @@ -1684,7 +1684,7 @@ def saveOtherModeHDefinitionAll(fMaterial, settings, tlut, defaults, f3d): fMaterial.mat_only_DL.commands.append(cmd) -def saveOtherModeHDefinitionIndividual(fMaterial, settings, tlut, defaults): +def saveOtherModeHDefinitionIndividual(fMaterial, settings, tlut, defaults): # TODO saveModeSetting(fMaterial, settings.g_mdsft_alpha_dither, defaults.g_mdsft_alpha_dither, DPSetAlphaDither) saveModeSetting(fMaterial, settings.g_mdsft_rgb_dither, defaults.g_mdsft_rgb_dither, DPSetColorDither) saveModeSetting(fMaterial, settings.g_mdsft_combkey, defaults.g_mdsft_combkey, DPSetCombineKey) From 407cd332a0eed82791fb34e02c370e7e9448c2aa Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 26 Apr 2025 17:53:35 +0100 Subject: [PATCH 08/32] speed ui, allow extra yuv case --- fast64_internal/f3d/f3d_material.py | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 206cae91a..36abcfe95 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -4807,7 +4807,10 @@ def get_used_textures(self, use_dict: dict = None) -> dict[int, TextureProperty] if self.uses_mipmap: return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} if use_dict is None: - use_dict = all_combiner_uses(self) + use_dict = { + "Texture 0": combiner_uses_tex0(self, self.cycle_type), + "Texture 1": combiner_uses_tex1(self, self.cycle_type), + } return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} @property @@ -4823,8 +4826,8 @@ def set_textures(self): @property def is_multi_tex(self): - use_dict = all_combiner_uses(self) - return use_dict["Texture 0"] and use_dict["Texture 1"] + cycle_type = self.cycle_type + return combiner_uses_tex0(self, cycle_type) and combiner_uses_tex1(self, cycle_type) def get_tlut_mode(self, only_auto=False, dont_raise=False): if self.pseudo_format in {"IHQ", "SHQ"}: @@ -4900,13 +4903,27 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, use_dict=None): if self.rdp_settings.g_mdsft_text_filt == "G_TF_POINT": return "G_TC_CONV" return "G_TC_FILTCONV" - elif not fmts or dont_raise: + elif not self.uses_mipmap or len(textures) <= 2: # in filtconv, tex0 is not converted, therefor can be non YUV + yuv_tex = next(i for i, tex in textures.items() if tex.tex_format == "YUV16") + if yuv_tex == 1: + return "G_TC_FILTCONV" + if dont_raise: + return None + raise PluginError( + "Texture 0 is YUV and texture 1 is not YUV.\nCannot use G_TC_FILTCONV to bypass convert in texture 0." + ) + elif not fmts: return None if only_auto else self.rdp_settings.g_mdsft_textconv - text = "Can't mix YUV and non-YUV textures." - for fmt in fmts: - fmt_textures = [str(i) for i, tex in textures.items() if tex.tex_format == fmt] - text += f"\n{fmt.lstrip('G_TT_')}: Texture{'s' if len(fmt_textures) > 1 else ''} {', '.join(fmt_textures)}" - raise PluginError(text) + else: + if dont_raise: + return None + text = "Can't mix more than 2 or mipmapped YUV and non-YUV textures." + for fmt in fmts: + fmt_textures = [str(i) for i, tex in textures.items() if tex.tex_format == fmt] + text += ( + f"\n{fmt.lstrip('G_TT_')}: Texture{'s' if len(fmt_textures) > 1 else ''} {', '.join(fmt_textures)}" + ) + raise PluginError(text) @property def tex_convert(self): From cc8a99d2895b18ca0ee900a0f5a78995c16dc411 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 26 Apr 2025 17:53:35 +0100 Subject: [PATCH 09/32] speed ui, allow extra yuv case --- fast64_internal/f3d/f3d_material.py | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 206cae91a..89b83f538 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -4807,7 +4807,10 @@ def get_used_textures(self, use_dict: dict = None) -> dict[int, TextureProperty] if self.uses_mipmap: return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} if use_dict is None: - use_dict = all_combiner_uses(self) + use_dict = { + "Texture 0": combiner_uses_tex0(self, self.cycle_type), + "Texture 1": combiner_uses_tex1(self, self.cycle_type), + } return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} @property @@ -4823,8 +4826,8 @@ def set_textures(self): @property def is_multi_tex(self): - use_dict = all_combiner_uses(self) - return use_dict["Texture 0"] and use_dict["Texture 1"] + cycle_type = self.cycle_type + return combiner_uses_tex0(self, cycle_type) and combiner_uses_tex1(self, cycle_type) def get_tlut_mode(self, only_auto=False, dont_raise=False): if self.pseudo_format in {"IHQ", "SHQ"}: @@ -4900,13 +4903,27 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, use_dict=None): if self.rdp_settings.g_mdsft_text_filt == "G_TF_POINT": return "G_TC_CONV" return "G_TC_FILTCONV" - elif not fmts or dont_raise: + elif len(fmts) == 2 and (not self.uses_mipmap or len(textures) == 2): + yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) + if yuv_tex == 1: # in filtconv, tex0 is not converted, therefor can be non YUV + return "G_TC_FILTCONV" + if dont_raise: + return None + raise PluginError( + "Texture 0 is YUV and texture 1 is not YUV.\nCannot use G_TC_FILTCONV to bypass convert in texture 0." + ) + elif not fmts: return None if only_auto else self.rdp_settings.g_mdsft_textconv - text = "Can't mix YUV and non-YUV textures." - for fmt in fmts: - fmt_textures = [str(i) for i, tex in textures.items() if tex.tex_format == fmt] - text += f"\n{fmt.lstrip('G_TT_')}: Texture{'s' if len(fmt_textures) > 1 else ''} {', '.join(fmt_textures)}" - raise PluginError(text) + else: + if dont_raise: + return None + text = "Can't mix more than 2 or mipmapped YUV and non-YUV textures." + for fmt in fmts: + fmt_textures = [str(i) for i, tex in textures.items() if tex.tex_format == fmt] + text += ( + f"\n{fmt.lstrip('G_TT_')}: Texture{'s' if len(fmt_textures) > 1 else ''} {', '.join(fmt_textures)}" + ) + raise PluginError(text) @property def tex_convert(self): From f4e28cbc0e472899c296ee245ca327f2218c26b0 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 27 Apr 2025 14:53:36 +0100 Subject: [PATCH 10/32] some more UI opts, force 2 cycle for textures --- fast64_internal/f3d/f3d_material.py | 73 +++++++++++++++++++---------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 89b83f538..e86900d93 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -506,7 +506,7 @@ def all_combiner_uses(f3d_mat: "F3DMaterialProperty", cycle_type: str = None) -> } useDict["Convert"] = ( combiner_uses(f3d_mat, ["K4", "K5"], cycle_type=cycle_type) - or f3d_mat.get_tex_convert(dont_raise=True, use_dict=useDict) != "G_TC_FILT" + or f3d_mat.get_tex_convert(dont_raise=True, tex_use={0: use_tex0, 1: use_tex1}) != "G_TC_FILT" ) return useDict @@ -679,14 +679,7 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): tex_conv = tlut_mode = tex_lod = tex_detail = mip_count = cycle_type = None if isinstance(dataHolder, F3DMaterialProperty): # TODO: proper auto mip count once we start using tex manager for preview and UI - tex_conv, tlut_mode, tex_lod, tex_detail, mip_count, cycle_type = ( - dataHolder.get_tex_convert(True, dont_raise=True), - dataHolder.get_tlut_mode(True, dont_raise=True), - dataHolder.get_tex_lod(True), - dataHolder.get_tex_detail(True), - 2 if dataHolder.gen_auto_mips else None, - dataHolder.get_cycle_type(True, dont_raise=True), - ) + tex_conv, tlut_mode, tex_lod, tex_detail, mip_count, cycle_type = dataHolder.get_all_auto_modes.values() prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") @@ -4796,38 +4789,47 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) + def get_tex_combiner_use(self, cycle_type: str = None) -> dict[int, bool]: + if cycle_type is None: + cycle_type = self.cycle_type + return { + 0: combiner_uses_tex0(self, cycle_type), + 1: combiner_uses_tex1(self, cycle_type), + } + @property def all_textures(self) -> list[TextureProperty]: return tuple(getattr(self, f"tex{i}") for i in range(8)) - def get_used_textures(self, use_dict: dict = None) -> dict[int, TextureProperty]: + def get_used_textures(self, tex_use: dict = None) -> dict[int, TextureProperty]: self.rdp_settings: RDPSettings if self.gen_pseudo_format or self.gen_auto_mips: return {0: self.all_textures[0]} if self.uses_mipmap: return {i: t for i, t in enumerate(self.all_textures[: self.rdp_settings.num_textures_mipmapped])} - if use_dict is None: - use_dict = { - "Texture 0": combiner_uses_tex0(self, self.cycle_type), - "Texture 1": combiner_uses_tex1(self, self.cycle_type), - } - return {i: t for i, t in enumerate(self.all_textures[:2]) if use_dict[f"Texture {i}"]} + if tex_use is None: + tex_use = self.get_tex_combiner_use() + return {i: t for i, t in enumerate(self.all_textures[:2]) if tex_use[i]} @property def used_textures(self) -> dict[int, TextureProperty]: return self.get_used_textures() - def get_set_textures(self, use_dict: dict = None): - return {i: tex for i, tex in self.get_used_textures(use_dict).items() if tex.tex_set} + def get_set_textures(self, tex_use: dict = None): + return {i: tex for i, tex in self.get_used_textures(tex_use).items() if tex.tex_set} @property def set_textures(self): return self.get_set_textures() + def check_multi_tex(self, tex_use: dict = None): + if tex_use is None: + tex_use = self.get_tex_combiner_use() + return tex_use[0] and tex_use[1] + @property def is_multi_tex(self): - cycle_type = self.cycle_type - return combiner_uses_tex0(self, cycle_type) and combiner_uses_tex1(self, cycle_type) + return self.check_multi_tex() def get_tlut_mode(self, only_auto=False, dont_raise=False): if self.pseudo_format in {"IHQ", "SHQ"}: @@ -4893,18 +4895,24 @@ def tex_detail(self) -> bool: def uses_mipmap(self) -> bool: return self.tex_lod == "G_TL_LOD" - def get_tex_convert(self, only_auto=False, dont_raise=False, use_dict=None): - textures = self.get_set_textures(use_dict) + def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | None = None): + textures = self.get_set_textures(tex_use) fmts: set[str] = set(tex.tex_format for tex in textures.values()) has_yuv = "YUV16" in fmts if self.pseudo_format in {"IHQ", "SHQ"} or (not has_yuv and fmts): return "G_TC_FILT" + yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) if len(fmts) == 1: if self.rdp_settings.g_mdsft_text_filt == "G_TF_POINT": return "G_TC_CONV" + if yuv_tex == 0 and not dont_raise: + raise PluginError( + "Texture 0 is YUV. But G_TC_FILTCONV\n" + "does not apply conversion to texture 0.\n" + "Only possible to convert with point filtering." + ) return "G_TC_FILTCONV" elif len(fmts) == 2 and (not self.uses_mipmap or len(textures) == 2): - yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) if yuv_tex == 1: # in filtconv, tex0 is not converted, therefor can be non YUV return "G_TC_FILTCONV" if dont_raise: @@ -4931,8 +4939,12 @@ def tex_convert(self): def get_cycle_type(self, only_auto=False, dont_raise=False): cur_cycle_type = self.rdp_settings.g_mdsft_cycletype - use_dict = all_combiner_uses(self, cur_cycle_type) - if self.uses_mipmap or self.get_tex_convert(dont_raise=dont_raise, use_dict=use_dict) == "G_TC_FILTCONV": + tex_use = self.get_tex_combiner_use(cur_cycle_type) + if ( + self.uses_mipmap + or (self.get_tex_convert(dont_raise=dont_raise, tex_use=tex_use) == "G_TC_FILTCONV") + or self.check_multi_tex(tex_use) + ): return "G_CYC_2CYCLE" return None if only_auto else cur_cycle_type @@ -4940,6 +4952,17 @@ def get_cycle_type(self, only_auto=False, dont_raise=False): def cycle_type(self): return self.get_cycle_type(False, dont_raise=True) + @property + def get_all_auto_modes(self): + return { + "g_mdsft_text_filt": self.get_tex_convert(True, dont_raise=True), + "g_mdsft_textlut": self.get_tlut_mode(True, dont_raise=True), + "g_mdsft_textlod": self.get_tex_lod(True), + "g_mdsft_textdetail": self.get_tex_detail(True), + "num_textures_mipmapped": 2 if self.gen_auto_mips else None, + "g_mdsft_cycletype": self.get_cycle_type(True, dont_raise=True), + } + def key(self) -> F3DMaterialHash: useDefaultLighting = self.set_lights and self.use_default_lighting return ( From be3bb67fffc24a52918f9970fcc7388ad7cedbab Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 27 Apr 2025 18:35:07 +0100 Subject: [PATCH 11/32] impl do not set other mode ui --- fast64_internal/f3d/f3d_enums.py | 169 +++++++++++++++++++++++- fast64_internal/f3d/f3d_material.py | 196 +++------------------------- 2 files changed, 186 insertions(+), 179 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 33eca0f2a..6aa6813f2 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -147,12 +147,31 @@ "0": ("0", 0), } +DO_NOT_SET = ( + "NONE", + "Don´t Set", + "In write different this means not attempting to set, in write all it means fetching the world default", + "X" +) + +def add_do_not_set(enum_list: list[tuple[str, str, str]]): + if enum_list and len(enum_list[0]) <= 3: + index = len(enum_list) + else: + index = next((i for i, e in enumerate(enum_list) if e[3] != i), len(enum_list)) + with_no_set = [(*DO_NOT_SET, index)] + [(*knd[:3], i) for i, knd in enumerate(enum_list)] + def run(self, context): + if getattr(context, "material", None) is None: + return enum_list + return with_no_set + return run + # hardware v2 enumAlphaDither = [ - ("G_AD_PATTERN", "Pattern", "Pattern"), - ("G_AD_NOTPATTERN", "NOT Pattern", "NOT Pattern"), - ("G_AD_NOISE", "Noise", "Noise"), - ("G_AD_DISABLE", "Disable", "Disable"), + ("G_AD_PATTERN", "Pattern", "Pattern", 0), + ("G_AD_NOTPATTERN", "NOT Pattern", "NOT Pattern", 1), + ("G_AD_NOISE", "Noise", "Noise", 2), + ("G_AD_DISABLE", "Disable", "Disable", 3), ] # hardware v2 @@ -437,3 +456,145 @@ ("Segment", "Segment", "Call a segmented DL to set the tint, can change at runtime"), ("Light", "From Light", "Automatically load tint color from selectable light slot. Tint level stored in DL"), ] + +bitSizeDict = { + "G_IM_SIZ_4b": 4, + "G_IM_SIZ_8b": 8, + "G_IM_SIZ_16b": 16, + "G_IM_SIZ_32b": 32, +} + +texBitSizeF3D = { + "I4": "G_IM_SIZ_4b", + "IA4": "G_IM_SIZ_4b", + "CI4": "G_IM_SIZ_4b", + "I8": "G_IM_SIZ_8b", + "IA8": "G_IM_SIZ_8b", + "CI8": "G_IM_SIZ_8b", + "RGBA16": "G_IM_SIZ_16b", + "IA16": "G_IM_SIZ_16b", + "YUV16": "G_IM_SIZ_16b", + "RGBA32": "G_IM_SIZ_32b", +} + +texFormatOf = { + "I4": "G_IM_FMT_I", + "IA4": "G_IM_FMT_IA", + "CI4": "G_IM_FMT_CI", + "I8": "G_IM_FMT_I", + "IA8": "G_IM_FMT_IA", + "CI8": "G_IM_FMT_CI", + "RGBA16": "G_IM_FMT_RGBA", + "IA16": "G_IM_FMT_IA", + "YUV16": "G_IM_FMT_YUV", + "RGBA32": "G_IM_FMT_RGBA", +} + + +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"), +] + +ootEnumDrawLayers = [ + ("Opaque", "Opaque", "Opaque"), + ("Transparent", "Transparent", "Transparent"), + ("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", +} + +enumF3DSource = [ + ("None", "None", "None"), + ("Texture", "Texture", "Texture"), + ("Tile Size", "Tile Size", "Tile Size"), + ("Primitive", "Primitive", "Primitive"), + ("Environment", "Environment", "Environment"), + ("Shade", "Shade", "Shade"), + ("Key", "Key", "Key"), + ("LOD Fraction", "LOD Fraction", "LOD Fraction"), + ("Convert", "Convert", "Convert"), +] + +defaultMaterialPresets = { + "Shaded Solid": {"SM64": "Shaded Solid", "OOT": "oot_shaded_solid"}, + "Shaded Texture": {"SM64": "Shaded Texture", "OOT": "oot_shaded_texture"}, +} + +F3D_GEO_MODES = { + "zBuffer": "g_zbuffer", + "shade": "g_shade", + "cullFront": "g_cull_front", + "cullBack": "g_cull_back", + "fog": "g_fog", + "lighting": "g_lighting", + "texGen": "g_tex_gen", + "texGenLinear": "g_tex_gen_linear", + "lod": "g_lod", + "shadeSmooth": "g_shade_smooth", +} + +F3DLX_GEO_MODES = { + "clipping": "g_clipping", +} + +F3DEX3_GEO_MODES = { + "ambientOcclusion": "g_ambocclusion", + "attroffsetZ": "g_attroffset_z_enable", + "attroffsetST": "g_attroffset_st_enable", + "packedNormals": "g_packed_normals", + "lightToAlpha": "g_lighttoalpha", + "specularLighting": "g_lighting_specular", + "fresnelToColor": "g_fresnel_color", + "fresnelToAlpha": "g_fresnel_alpha", +} + + +T3D_GEO_MODES = { + "cullFront": "g_cull_front", + "cullBack": "g_cull_back", + "fog": "g_fog", + "texGen": "g_tex_gen", +} + + +OTHERMODE_H_ATTRS = [ + ("alphaDither", "g_mdsft_alpha_dither", "G_AD_DISABLE"), + ("colorDither", "g_mdsft_rgb_dither", "G_CD_MAGICSQ"), + ("chromaKey", "g_mdsft_combkey", "G_CK_NONE"), + ("textureConvert", "g_mdsft_textconv", "G_TC_CONV"), + ("textureFilter", "g_mdsft_text_filt", "G_TF_POINT"), + ("lutFormat", "g_mdsft_textlut", "G_TT_NONE"), + ("textureLoD", "g_mdsft_textlod", "G_TL_TILE"), + ("textureDetail", "g_mdsft_textdetail", "G_TD_CLAMP"), + ("perspectiveCorrection", "g_mdsft_textpersp", "G_TP_NONE"), + ("cycleType", "g_mdsft_cycletype", "G_CYC_1CYCLE"), + ("pipelineMode", "g_mdsft_pipeline", "G_PM_NPRIMITIVE"), +] + +OTHERMODE_L_ATTRS = [ + ("alphaCompare", "g_mdsft_alpha_compare", "G_AC_NONE"), + ("zSourceSelection", "g_mdsft_zsrcsel", "G_ZS_PIXEL"), +] diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index e86900d93..76271c5b8 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -58,75 +58,6 @@ logging.basicConfig(format="%(asctime)s: %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") logger = logging.getLogger(__name__) -bitSizeDict = { - "G_IM_SIZ_4b": 4, - "G_IM_SIZ_8b": 8, - "G_IM_SIZ_16b": 16, - "G_IM_SIZ_32b": 32, -} - -texBitSizeF3D = { - "I4": "G_IM_SIZ_4b", - "IA4": "G_IM_SIZ_4b", - "CI4": "G_IM_SIZ_4b", - "I8": "G_IM_SIZ_8b", - "IA8": "G_IM_SIZ_8b", - "CI8": "G_IM_SIZ_8b", - "RGBA16": "G_IM_SIZ_16b", - "IA16": "G_IM_SIZ_16b", - "YUV16": "G_IM_SIZ_16b", - "RGBA32": "G_IM_SIZ_32b", -} - -texFormatOf = { - "I4": "G_IM_FMT_I", - "IA4": "G_IM_FMT_IA", - "CI4": "G_IM_FMT_CI", - "I8": "G_IM_FMT_I", - "IA8": "G_IM_FMT_IA", - "CI8": "G_IM_FMT_CI", - "RGBA16": "G_IM_FMT_RGBA", - "IA16": "G_IM_FMT_IA", - "YUV16": "G_IM_FMT_YUV", - "RGBA32": "G_IM_FMT_RGBA", -} - - -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"), -] - -ootEnumDrawLayers = [ - ("Opaque", "Opaque", "Opaque"), - ("Transparent", "Transparent", "Transparent"), - ("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", -} - def menu_items_enum(_self, context): items = ["Combiner", "Sources"] @@ -136,60 +67,6 @@ def menu_items_enum(_self, context): return [(item, item, item) for item in items] -enumF3DSource = [ - ("None", "None", "None"), - ("Texture", "Texture", "Texture"), - ("Tile Size", "Tile Size", "Tile Size"), - ("Primitive", "Primitive", "Primitive"), - ("Environment", "Environment", "Environment"), - ("Shade", "Shade", "Shade"), - ("Key", "Key", "Key"), - ("LOD Fraction", "LOD Fraction", "LOD Fraction"), - ("Convert", "Convert", "Convert"), -] - -defaultMaterialPresets = { - "Shaded Solid": {"SM64": "Shaded Solid", "OOT": "oot_shaded_solid"}, - "Shaded Texture": {"SM64": "Shaded Texture", "OOT": "oot_shaded_texture"}, -} - -F3D_GEO_MODES = { - "zBuffer": "g_zbuffer", - "shade": "g_shade", - "cullFront": "g_cull_front", - "cullBack": "g_cull_back", - "fog": "g_fog", - "lighting": "g_lighting", - "texGen": "g_tex_gen", - "texGenLinear": "g_tex_gen_linear", - "lod": "g_lod", - "shadeSmooth": "g_shade_smooth", -} - -F3DLX_GEO_MODES = { - "clipping": "g_clipping", -} - -F3DEX3_GEO_MODES = { - "ambientOcclusion": "g_ambocclusion", - "attroffsetZ": "g_attroffset_z_enable", - "attroffsetST": "g_attroffset_st_enable", - "packedNormals": "g_packed_normals", - "lightToAlpha": "g_lighttoalpha", - "specularLighting": "g_lighting_specular", - "fresnelToColor": "g_fresnel_color", - "fresnelToAlpha": "g_fresnel_alpha", -} - - -T3D_GEO_MODES = { - "cullFront": "g_cull_front", - "cullBack": "g_cull_back", - "fog": "g_fog", - "texGen": "g_tex_gen", -} - - def geo_modes_in_ucode(UCODE_VER: str): geo_modes = {} if is_ucode_f3d(UCODE_VER): @@ -1859,13 +1736,15 @@ def set_output_node_groups(material: Material): output_node = nodes["OUTPUT"] f3dMat: "F3DMaterialProperty" = material.f3d_mat cycle = f3dMat.cycle_type.lstrip("G_CYC_").rstrip("_CYCLE") + if cycle not in {"1", "2"}: # TODO: fill and copy? + cycle = "1" output_method = get_output_method(material) if bpy.app.version < (4, 2, 0) and output_method == "CLIP": output_method = "XLU" material.alpha_threshold = 0.125 output_group_name = f"OUTPUT_{cycle}CYCLE_{output_method}" - output_group = bpy.data.node_groups[output_group_name] + output_group = bpy.data.node_groups.get(output_group_name) output_node.node_tree = output_group for inp in output_node.inputs: @@ -3566,50 +3445,43 @@ class RDPSettings(PropertyGroup): # v2 only g_mdsft_alpha_dither: bpy.props.EnumProperty( name="Alpha Dither", - items=enumAlphaDither, - default="G_AD_DISABLE", + items=add_do_not_set(enumAlphaDither), update=update_node_values_with_preset, description="Applies your choice dithering type to output framebuffer alpha. Dithering is used to convert high precision source colors into lower precision framebuffer values", ) # v2 only g_mdsft_rgb_dither: bpy.props.EnumProperty( name="RGB Dither", - items=enumRGBDither, - default="G_CD_MAGICSQ", + items=add_do_not_set(enumRGBDither), update=update_node_values_with_preset, description="Applies your choice dithering type to output framebuffer color. Dithering is used to convert high precision source colors into lower precision framebuffer values", ) g_mdsft_combkey: bpy.props.EnumProperty( name="Chroma Key", - items=enumCombKey, - default="G_CK_NONE", + items=add_do_not_set(enumCombKey), update=update_node_values_with_preset, description="Turns on/off the chroma key. Chroma key requires a special setup to work properly", ) g_mdsft_textconv: bpy.props.EnumProperty( name="Texture Convert", - items=enumTextConv, - default="G_TC_CONV", + items=add_do_not_set(enumTextConv), update=update_node_values_with_preset, description="Sets the function of the texture convert unit, to do texture filtering, YUV to RGB conversion, or both", ) g_mdsft_text_filt: bpy.props.EnumProperty( name="Texture Filter", - items=enumTextFilt, - default="G_TF_POINT", + items=add_do_not_set(enumTextFilt), update=update_node_values_without_preset, description="Applies your choice of filtering to texels", ) g_mdsft_textlut: bpy.props.EnumProperty( name="Texture LUT", - items=enumTextLUT, - default="G_TT_NONE", + items=add_do_not_set(enumTextLUT), description="Changes texture look up table (LUT) behavior. This property is auto set if you choose a CI texture", ) g_mdsft_textlod: bpy.props.EnumProperty( name="Texture LOD", - items=enumTextLOD, - default="G_TL_TILE", + items=add_do_not_set(enumTextLOD), update=update_node_values_with_preset, description="Turns on/off the use of LoD on textures. LoD textures change the used tile based on the texel/pixel ratio", ) @@ -3622,37 +3494,32 @@ class RDPSettings(PropertyGroup): ) g_mdsft_textdetail: bpy.props.EnumProperty( name="Texture Detail", - items=enumTextDetail, - default="G_TD_CLAMP", + items=add_do_not_set(enumTextDetail), update=update_node_values_with_preset, description="Changes type of LoD usage. Affects how tiles are selected based on texel magnification. Only works when G_TL_LOD is selected", ) g_mdsft_textpersp: bpy.props.EnumProperty( name="Texture Perspective Correction", - items=enumTextPersp, - default="G_TP_NONE", + items=add_do_not_set(enumTextPersp), update=update_node_values_with_preset, description="Turns on/off texture perspective correction", ) g_mdsft_cycletype: bpy.props.EnumProperty( name="Cycle Type", - items=enumCycleType, - default="G_CYC_1CYCLE", + items=add_do_not_set(enumCycleType), update=update_node_values_with_preset, description="Changes RDP pipeline configuration. For normal textured triangles use one or two cycle mode", ) # v1 only g_mdsft_color_dither: bpy.props.EnumProperty( name="Color Dither", - items=enumColorDither, - default="G_CD_ENABLE", + items=add_do_not_set(enumColorDither), update=update_node_values_with_preset, description="Applies your choice dithering type to output frambuffer", ) g_mdsft_pipeline: bpy.props.EnumProperty( name="Pipeline Span Buffer Coherency", - items=enumPipelineMode, - default="G_PM_NPRIMITIVE", + items=add_do_not_set(enumPipelineMode), update=update_node_values_with_preset, description="Changes primitive rasterization timing by adding syncs after tri draws. Vanilla SM64 has synchronization issues which could cause a crash if not using 1 prim. For any modern SM64 hacking project or other game N-prim should always be used", ) @@ -3660,15 +3527,13 @@ class RDPSettings(PropertyGroup): # lower half mode g_mdsft_alpha_compare: bpy.props.EnumProperty( name="Alpha Compare", - items=enumAlphaCompare, - default="G_AC_NONE", + items=add_do_not_set(enumAlphaCompare), update=update_node_values_with_preset, description="Uses alpha comparisons to decide if a pixel should be written. Applies before blending", ) g_mdsft_zsrcsel: bpy.props.EnumProperty( name="Z Source Selection", - items=enumDepthSource, - default="G_ZS_PIXEL", + items=add_do_not_set(enumDepthSource), update=update_node_values_with_preset, description="Changes screen-space Z value source used for Z-Buffer calculations", ) @@ -3843,33 +3708,14 @@ def geo_mode_from_dict(self, data: dict): for key, attr in self.geo_mode_attributes.items(): setattr(self, attr, data.get(key, False)) - other_mode_h_attributes = [ - ("alphaDither", "g_mdsft_alpha_dither", "G_AD_DISABLE"), - ("colorDither", "g_mdsft_rgb_dither", "G_CD_MAGICSQ"), - ("chromaKey", "g_mdsft_combkey", "G_CK_NONE"), - ("textureConvert", "g_mdsft_textconv", "G_TC_CONV"), - ("textureFilter", "g_mdsft_text_filt", "G_TF_POINT"), - ("lutFormat", "g_mdsft_textlut", "G_TT_NONE"), - ("textureLoD", "g_mdsft_textlod", "G_TL_TILE"), - ("textureDetail", "g_mdsft_textdetail", "G_TD_CLAMP"), - ("perspectiveCorrection", "g_mdsft_textpersp", "G_TP_NONE"), - ("cycleType", "g_mdsft_cycletype", "G_CYC_1CYCLE"), - ("pipelineMode", "g_mdsft_pipeline", "G_PM_NPRIMITIVE"), - ] - def other_mode_h_to_dict(self, lut_format=None): - data = self.attributes_to_dict(self.other_mode_h_attributes) + data = self.attributes_to_dict(OTHERMODE_H_ATTRS) if lut_format: data["lutFormat"] = lut_format return data def other_mode_h_from_dict(self, data: dict): - self.attributes_from_dict(data, self.other_mode_h_attributes) - - other_mode_l_attributes = [ - ("alphaCompare", "g_mdsft_alpha_compare", "G_AC_NONE"), - ("zSourceSelection", "g_mdsft_zsrcsel", "G_ZS_PIXEL"), - ] + self.attributes_from_dict(data, OTHERMODE_H_ATTRS) rendermode_flag_attributes = [ ("aa", "aa_en", False), @@ -3885,7 +3731,7 @@ def other_mode_h_from_dict(self, data: dict): ] def other_mode_l_to_dict(self): - data = self.attributes_to_dict(self.other_mode_l_attributes) + data = self.attributes_to_dict(OTHERMODE_L_ATTRS) if self.g_mdsft_zsrcsel == "G_ZS_PRIM": data["primDepth"] = self.prim_depth.to_dict() if self.set_rendermode: @@ -3914,7 +3760,7 @@ def other_mode_l_to_dict(self): return data def other_mode_l_from_dict(self, data: dict): - self.attributes_from_dict(data, self.other_mode_l_attributes) + self.attributes_from_dict(data, OTHERMODE_L_ATTRS) self.prim_depth.from_dict(data.get("primDepth", {})) render_mode = data.get("renderMode", {}) From 5c45437918b45c866a12566f0a0ab37a2d2dbe37 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 27 Apr 2025 19:09:56 +0100 Subject: [PATCH 12/32] use NONE for sm64 othermodes --- fast64_internal/f3d/f3d_material_presets.py | 407 ++++++++++---------- 1 file changed, 196 insertions(+), 211 deletions(-) diff --git a/fast64_internal/f3d/f3d_material_presets.py b/fast64_internal/f3d/f3d_material_presets.py index da4c7f62a..f121c87df 100644 --- a/fast64_internal/f3d/f3d_material_presets.py +++ b/fast64_internal/f3d/f3d_material_presets.py @@ -1783,20 +1783,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -1895,20 +1895,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2007,20 +2007,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_2CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = True f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2119,20 +2119,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_2CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = True f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2231,20 +2231,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_2CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = True f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2344,19 +2344,19 @@ f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2455,20 +2455,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2567,20 +2567,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2679,20 +2679,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2791,20 +2791,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -2903,20 +2903,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -3015,20 +3015,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -3127,20 +3127,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -3239,20 +3239,20 @@ f3d_mat.rdp_settings.g_lod = False f3d_mat.rdp_settings.g_shade_smooth = True f3d_mat.rdp_settings.g_clipping = False -f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_NOISE' -f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' -f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' -f3d_mat.rdp_settings.g_mdsft_textconv = 'G_TC_FILT' -f3d_mat.rdp_settings.g_mdsft_text_filt = 'G_TF_BILERP' -f3d_mat.rdp_settings.g_mdsft_textlut = 'G_TT_NONE' -f3d_mat.rdp_settings.g_mdsft_textlod = 'G_TL_TILE' -f3d_mat.rdp_settings.g_mdsft_textdetail = 'G_TD_CLAMP' -f3d_mat.rdp_settings.g_mdsft_textpersp = 'G_TP_PERSP' -f3d_mat.rdp_settings.g_mdsft_cycletype = 'G_CYC_1CYCLE' -f3d_mat.rdp_settings.g_mdsft_color_dither = 'G_CD_ENABLE' -f3d_mat.rdp_settings.g_mdsft_pipeline = 'G_PM_1PRIMITIVE' -f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'G_AC_NONE' -f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'G_ZS_PIXEL' +f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_combkey = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textconv = 'NONE' +f3d_mat.rdp_settings.g_mdsft_text_filt = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlut = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textlod = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textdetail = 'NONE' +f3d_mat.rdp_settings.g_mdsft_textpersp = 'NONE' +f3d_mat.rdp_settings.g_mdsft_cycletype = 'NONE' +f3d_mat.rdp_settings.g_mdsft_color_dither = 'NONE' +f3d_mat.rdp_settings.g_mdsft_pipeline = 'NONE' +f3d_mat.rdp_settings.g_mdsft_alpha_compare = 'NONE' +f3d_mat.rdp_settings.g_mdsft_zsrcsel = 'NONE' f3d_mat.rdp_settings.clip_ratio = 1 f3d_mat.rdp_settings.set_rendermode = False f3d_mat.rdp_settings.rendermode_advanced_enabled = False @@ -6405,6 +6405,10 @@ f"oot_{key}": value + 'f3d_mat.presetName = "Oot " + f3d_mat.presetName' for key, value in homebrew_and_oot.items() }, + "mk64": { + f"mk64_{key}": value + 'f3d_mat.presetName = "MK64 " + f3d_mat.presetName' + for key, value in homebrew_and_oot.items() + }, "oot_f3dex3": { "oot_cel_4_blend_tex_vcol_ao": oot_cel_4_blend_tex_vcol_ao, "oot_cel_blend_tex_vcol_ltcol": oot_cel_blend_tex_vcol_ltcol, @@ -6444,23 +6448,4 @@ "sm64_vertex_colored_texture": sm64_vertex_colored_texture, "sm64_vertex_colored_texture_transparent": sm64_vertex_colored_texture_transparent, }, - "mk64": { - "shaded_environment_mapped": shaded_environment_mapped, - "shaded_environment_mapped_transparent": shaded_environment_mapped_transparent, - "shaded_multitexture_lerp": shaded_multitexture_lerp, - "shaded_multitexture_lerp_transparent": shaded_multitexture_lerp_transparent, - "shaded_solid": shaded_solid, - "shaded_multitexture_lerp_transparent_vertex_alpha": shaded_multitexture_lerp_transparent_vertex_alpha, - "shaded_solid_transparent": shaded_solid_transparent, - "shaded_texture": shaded_texture, - "shaded_texture_cutout": shaded_texture_cutout, - "shaded_texture_transparent": shaded_texture_transparent, - "shaded_texture_transparent_vertex_alpha": shaded_texture_transparent_vertex_alpha, - "unlit_texture": unlit_texture, - "unlit_texture_cutout": unlit_texture_cutout, - "unlit_texture_transparent": unlit_texture_transparent, - "vertex_colored_texture": vertex_colored_texture, - "vertex_colored_texture_cutout": vertex_colored_texture_cutout, - "vertex_colored_texture_transparent": vertex_colored_texture_transparent, - }, } From 1e6cadba5091f19707a21cd2b33b9bf89b00113e Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 27 Apr 2025 19:37:14 +0100 Subject: [PATCH 13/32] rename properties for consistency --- fast64_internal/f3d/f3d_enums.py | 41 +++++++++++------- fast64_internal/f3d/f3d_material.py | 56 ++++++++++++------------- fast64_internal/sm64/sm64_f3d_writer.py | 4 +- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 6aa6813f2..1c52fe77e 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -1,3 +1,6 @@ +from typing import NamedTuple + + combiner_enums = { "Case A": ( ("COMBINED", "Combined Color", "Combined Color"), @@ -151,21 +154,25 @@ "NONE", "Don´t Set", "In write different this means not attempting to set, in write all it means fetching the world default", - "X" + "X", ) + def add_do_not_set(enum_list: list[tuple[str, str, str]]): if enum_list and len(enum_list[0]) <= 3: index = len(enum_list) else: index = next((i for i, e in enumerate(enum_list) if e[3] != i), len(enum_list)) with_no_set = [(*DO_NOT_SET, index)] + [(*knd[:3], i) for i, knd in enumerate(enum_list)] + def run(self, context): if getattr(context, "material", None) is None: return enum_list return with_no_set + return run + # hardware v2 enumAlphaDither = [ ("G_AD_PATTERN", "Pattern", "Pattern", 0), @@ -580,21 +587,27 @@ def run(self, context): } +class PropWithDefault(NamedTuple): + dict_name: str + prop: str + default: str + + OTHERMODE_H_ATTRS = [ - ("alphaDither", "g_mdsft_alpha_dither", "G_AD_DISABLE"), - ("colorDither", "g_mdsft_rgb_dither", "G_CD_MAGICSQ"), - ("chromaKey", "g_mdsft_combkey", "G_CK_NONE"), - ("textureConvert", "g_mdsft_textconv", "G_TC_CONV"), - ("textureFilter", "g_mdsft_text_filt", "G_TF_POINT"), - ("lutFormat", "g_mdsft_textlut", "G_TT_NONE"), - ("textureLoD", "g_mdsft_textlod", "G_TL_TILE"), - ("textureDetail", "g_mdsft_textdetail", "G_TD_CLAMP"), - ("perspectiveCorrection", "g_mdsft_textpersp", "G_TP_NONE"), - ("cycleType", "g_mdsft_cycletype", "G_CYC_1CYCLE"), - ("pipelineMode", "g_mdsft_pipeline", "G_PM_NPRIMITIVE"), + PropWithDefault("alphaDither", "g_mdsft_alpha_dither", "G_AD_DISABLE"), + PropWithDefault("colorDither", "g_mdsft_rgb_dither", "G_CD_MAGICSQ"), + PropWithDefault("chromaKey", "g_mdsft_combkey", "G_CK_NONE"), + PropWithDefault("textureConvert", "g_mdsft_textconv", "G_TC_CONV"), + PropWithDefault("textureFilter", "g_mdsft_text_filt", "G_TF_POINT"), + PropWithDefault("lutFormat", "g_mdsft_textlut", "G_TT_NONE"), + PropWithDefault("textureLoD", "g_mdsft_textlod", "G_TL_TILE"), + PropWithDefault("textureDetail", "g_mdsft_textdetail", "G_TD_CLAMP"), + PropWithDefault("perspectiveCorrection", "g_mdsft_textpersp", "G_TP_NONE"), + PropWithDefault("cycleType", "g_mdsft_cycletype", "G_CYC_1CYCLE"), + PropWithDefault("pipelineMode", "g_mdsft_pipeline", "G_PM_NPRIMITIVE"), ] OTHERMODE_L_ATTRS = [ - ("alphaCompare", "g_mdsft_alpha_compare", "G_AC_NONE"), - ("zSourceSelection", "g_mdsft_zsrcsel", "G_ZS_PIXEL"), + PropWithDefault("alphaCompare", "g_mdsft_alpha_compare", "G_AC_NONE"), + PropWithDefault("zSourceSelection", "g_mdsft_zsrcsel", "G_ZS_PIXEL"), ] diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 76271c5b8..937e3ff0c 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -181,7 +181,7 @@ def get_with_default(preset, default): # want, then disable it, and have it still previewed that way. return getattr(f3d, preset, default) - is_two_cycle = f3d_mat.cycle_type == "G_CYC_2CYCLE" + is_two_cycle = f3d_mat.cycletype == "G_CYC_2CYCLE" if is_two_cycle: r1 = get_with_default(cycle_1, f3d.G_RM_FOG_SHADE_A) r2 = get_with_default(cycle_2, f3d.G_RM_AA_ZB_OPA_SURF2) @@ -221,7 +221,7 @@ def is_blender_equation_equal(f3d_mat: "F3DMaterialProperty", cycle: int, p: str settings = f3d_mat.rdp_settings assert cycle in {1, 2, -1} # -1 = last cycle if cycle == -1: - cycle = 2 if f3d_mat.cycle_type else 1 + cycle = 2 if f3d_mat.cycletype else 1 return ( getattr(settings, f"blend_p{cycle}") == p and getattr(settings, f"blend_a{cycle}") == a @@ -338,7 +338,7 @@ def combiner_uses( cycle_type: str = None, ): if cycle_type is None: - cycle_type = f3dMat.cycle_type + cycle_type = f3dMat.cycletype is_two_cycle = cycle_type == "G_CYC_2CYCLE" for i in range(1, 3): if i == 1 and not checkCycle1 or i == 2 and (not checkCycle2 or not is_two_cycle): @@ -553,22 +553,22 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): icon="TRIA_DOWN" if dataHolder.menu_upper else "TRIA_RIGHT", ) if not useDropdown or dataHolder.menu_upper: - tex_conv = tlut_mode = tex_lod = tex_detail = mip_count = cycle_type = None + tex_conv = textlut = textlod = textdetail = mip_count = cycle_type = None if isinstance(dataHolder, F3DMaterialProperty): # TODO: proper auto mip count once we start using tex manager for preview and UI - tex_conv, tlut_mode, tex_lod, tex_detail, mip_count, cycle_type = dataHolder.get_all_auto_modes.values() + tex_conv, textlut, textlod, textdetail, mip_count, cycle_type = dataHolder.get_all_auto_modes.values() prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") draw_forced(inputGroup, settings, "g_mdsft_textconv", tex_conv is not None, "Texture Convert", tex_conv) prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") - draw_forced(inputGroup, settings, "g_mdsft_textlut", tlut_mode is not None, "Texture LUT", tlut_mode) - draw_forced(inputGroup, settings, "g_mdsft_textlod", tex_lod is not None, "Texture LOD", tex_lod) - if settings.g_mdsft_textlod == "G_TL_LOD" or tex_lod: + draw_forced(inputGroup, settings, "g_mdsft_textlut", textlut is not None, "Texture LUT", textlut) + draw_forced(inputGroup, settings, "g_mdsft_textlod", textlod is not None, "Texture LOD", textlod) + if settings.g_mdsft_textlod == "G_TL_LOD" or textlod: draw_forced( inputGroup, settings, "num_textures_mipmapped", mip_count is not None, "Number of Mipmaps", mip_count ) - draw_forced(inputGroup, settings, "g_mdsft_textdetail", tex_detail is not None, "Texture Detail", tex_detail) + draw_forced(inputGroup, settings, "g_mdsft_textdetail", textdetail is not None, "Texture Detail", textdetail) prop_split(inputGroup, settings, "g_mdsft_textpersp", "Texture Perspective Correction") draw_forced(inputGroup, settings, "g_mdsft_cycletype", cycle_type is not None, "Cycle Type", cycle_type) prop_split(inputGroup, settings, "g_mdsft_pipeline", "Pipeline Span Buffer Coherency") @@ -806,7 +806,7 @@ def ui_convert(self, material, layout, showCheckBox): return inputGroup def ui_lower_render_mode(self, material: "F3DMaterialProperty", layout, useDropdown): - is_two_cycle = material.cycle_type == "G_CYC_2CYCLE" + is_two_cycle = material.cycletype == "G_CYC_2CYCLE" # cycle independent inputGroup = layout.column() if useDropdown: @@ -1236,7 +1236,7 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl r.label(text=f"{letter}{' Alpha' if isAlpha else ''}:") r.prop(combiner, f"{letter}{'_alpha' if isAlpha else ''}", text="") - is_two_cycle = f3dMat.cycle_type == "G_CYC_2CYCLE" + is_two_cycle = f3dMat.cycletype == "G_CYC_2CYCLE" combinerBox = layout.box() combinerBox.prop(f3dMat, "set_combiner", text="Color Combiner (Color = (A - B) * C + D)") @@ -1337,7 +1337,7 @@ def draw(self, context): row.operator(AddPresetF3D.bl_idname, text="", icon="ADD") row.operator(AddPresetF3D.bl_idname, text="", icon="REMOVE").remove_active = True - if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and f3dMat.cycle_type == "G_CYC_2CYCLE": + if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and f3dMat.cycletype == "G_CYC_2CYCLE": multilineLabel( layout.box(), "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" @@ -1735,8 +1735,8 @@ def set_output_node_groups(material: Material): nodes = material.node_tree.nodes output_node = nodes["OUTPUT"] f3dMat: "F3DMaterialProperty" = material.f3d_mat - cycle = f3dMat.cycle_type.lstrip("G_CYC_").rstrip("_CYCLE") - if cycle not in {"1", "2"}: # TODO: fill and copy? + cycle = f3dMat.cycletype.lstrip("G_CYC_").rstrip("_CYCLE") + if cycle not in {"1", "2"}: # TODO: fill and copy? cycle = "1" output_method = get_output_method(material) if bpy.app.version < (4, 2, 0) and output_method == "CLIP": @@ -2175,13 +2175,11 @@ def update_tex_values_manual(material: Material, context, prop_path=None): nodes = material.node_tree.nodes texture_settings = nodes["TextureSettings"] texture_inputs: NodeInputs = texture_settings.inputs - useDict = all_combiner_uses(f3dMat) if f3dMat.uv_basis == "": f3dMat.uv_basis = str(max(f3dMat.set_textures.keys()) if f3dMat.set_textures else -1) - tex0_used = useDict["Texture 0"] - tex1_used = useDict["Texture 1"] + tex0_used, tex1_used = f3dMat.get_tex_combiner_use().values() if not tex0_used and not tex1_used: texture_settings.mute = True @@ -2211,10 +2209,10 @@ def update_tex_values_manual(material: Material, context, prop_path=None): texture_inputs["1 S TexSize"].default_value = f3dMat.tex1.tex.size[0] texture_inputs["1 T TexSize"].default_value = f3dMat.tex1.tex.size[0] - uv_basis: ShaderNodeGroup = nodes["UV Basis"] + uv_basis: ShaderNodeGroup = nodes["UV Basis"] # TODO if f3dMat.uv_basis == "TEXEL0": uv_basis.node_tree = bpy.data.node_groups["UV Basis 0"] - else: + elif f3dMat.uv_basis == "TEXEL1": uv_basis.node_tree = bpy.data.node_groups["UV Basis 1"] if not isTexGen: @@ -2939,7 +2937,7 @@ def is_yuv(self) -> bool: return self.tex_format in {"YUV16"} @property - def tlut_mode(self): + def textlut(self): return f"G_TT_{self.ci_format if self.is_ci else 'NONE'}" @property @@ -4637,7 +4635,7 @@ class F3DMaterialProperty(PropertyGroup): def get_tex_combiner_use(self, cycle_type: str = None) -> dict[int, bool]: if cycle_type is None: - cycle_type = self.cycle_type + cycle_type = self.cycletype return { 0: combiner_uses_tex0(self, cycle_type), 1: combiner_uses_tex1(self, cycle_type), @@ -4680,7 +4678,7 @@ def is_multi_tex(self): def get_tlut_mode(self, only_auto=False, dont_raise=False): if self.pseudo_format in {"IHQ", "SHQ"}: return "G_TT_NONE" - tlut_modes = set(tex.tlut_mode for tex in self.set_textures.values()) + tlut_modes = set(tex.textlut for tex in self.set_textures.values()) if len(tlut_modes) == 1: return list(tlut_modes)[0] elif len(tlut_modes) == 0 or dont_raise: @@ -4691,17 +4689,17 @@ def get_tlut_mode(self, only_auto=False, dont_raise=False): else "CI textures must use the same CI format." ) for tlut in tlut_modes: - textures = [str(i) for i, tex in self.set_textures.items() if tex.tlut_mode == tlut] + textures = [str(i) for i, tex in self.set_textures.items() if tex.textlut == tlut] text += f"\n{tlut.lstrip('G_TT_')}: Texture{'s' if len(textures) > 1 else ''} {', '.join(textures)}" raise PluginError(text) @property - def tlut_mode(self): + def textlut(self): return self.get_tlut_mode(dont_raise=True) @property def is_ci(self): - return self.tlut_mode in {"G_TT_RGBA16", "G_TT_IA16"} + return self.textlut in {"G_TT_RGBA16", "G_TT_IA16"} @property def pseudo_format(self): @@ -4725,7 +4723,7 @@ def get_tex_lod(self, only_auto=False) -> bool: return None if only_auto else self.rdp_settings.g_mdsft_textlod @property - def tex_lod(self) -> bool: + def textlod(self) -> bool: return self.get_tex_lod(False) def get_tex_detail(self, only_auto=False) -> bool: @@ -4734,12 +4732,12 @@ def get_tex_detail(self, only_auto=False) -> bool: return None if only_auto else self.rdp_settings.g_mdsft_textdetail @property - def tex_detail(self) -> bool: + def textdetail(self) -> bool: return self.get_tex_detail(False) @property def uses_mipmap(self) -> bool: - return self.tex_lod == "G_TL_LOD" + return self.textlod == "G_TL_LOD" def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | None = None): textures = self.get_set_textures(tex_use) @@ -4795,7 +4793,7 @@ def get_cycle_type(self, only_auto=False, dont_raise=False): return None if only_auto else cur_cycle_type @property - def cycle_type(self): + def cycletype(self): return self.get_cycle_type(False, dont_raise=True) @property diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index f0f929f7a..75a784c48 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -300,7 +300,7 @@ def modifyDLForHUD(data): def exportTexRectCommon(texProp, name, convertTextureData): - use_copy_mode = texProp.tlut_mode == "G_TT_RGBA16" or texProp.tex_format == "RGBA16" + use_copy_mode = texProp.textlut == "G_TT_RGBA16" or texProp.tex_format == "RGBA16" defaults = create_or_get_world(bpy.context.scene).rdp_defaults @@ -323,7 +323,7 @@ def exportTexRectCommon(texProp, name, convertTextureData): fMaterial.mat_only_DL.commands.append(DPSetRenderMode(["G_RM_AA_XLU_SURF", "G_RM_AA_XLU_SURF2"], None)) fMaterial.revert.commands.append(DPSetRenderMode(["G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"], None)) - saveModeSetting(fMaterial, texProp.tlut_mode, defaults.g_mdsft_textlut, DPSetTextureLUT) + saveModeSetting(fMaterial, texProp.textlut, defaults.g_mdsft_textlut, DPSetTextureLUT) ti = TexInfo() ti.fromProp(texProp, index=0, ignore_tex_set=True) ti.materialless_setup() From d44c0831dbdf128001b47ed819a7727b7e5c1d8d Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 27 Apr 2025 21:28:16 +0100 Subject: [PATCH 14/32] finish ui part --- fast64_internal/f3d/f3d_enums.py | 52 ++++++++----- fast64_internal/f3d/f3d_material.py | 117 +++++++++++++--------------- fast64_internal/utility.py | 5 +- 3 files changed, 92 insertions(+), 82 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 1c52fe77e..143478038 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -589,25 +589,39 @@ def run(self, context): class PropWithDefault(NamedTuple): dict_name: str - prop: str default: str + name: str = "" + + +OTHERMODE_H_ATTRS = { + "g_mdsft_alpha_dither": PropWithDefault("alphaDither", "G_AD_DISABLE", "Alpha Dither"), + "g_mdsft_rgb_dither": PropWithDefault("colorDither", "G_CD_MAGICSQ", "RGB Dither"), + "g_mdsft_combkey": PropWithDefault("chromaKey", "G_CK_NONE", "Chroma Key"), + "g_mdsft_textconv": PropWithDefault("textureConvert", "G_TC_CONV", "Texture Convert"), + "g_mdsft_text_filt": PropWithDefault("textureFilter", "G_TF_POINT", "Texture Filter"), + "g_mdsft_textlut": PropWithDefault("lutFormat", "G_TT_NONE", "Texture LUT"), + "num_textures_mipmapped": PropWithDefault("numTexturesMipmapped", 2, "Number of Mipmaps"), + "g_mdsft_textlod": PropWithDefault("textureLoD", "G_TL_TILE", "Texture LoD"), + "g_mdsft_textdetail": PropWithDefault("textureDetail", "G_TD_CLAMP", "Texture Detail"), + "g_mdsft_textpersp": PropWithDefault("perspectiveCorrection", "G_TP_NONE", "Texture Perspective Correction"), + "g_mdsft_cycletype": PropWithDefault("cycleType", "G_CYC_1CYCLE", "Cycle Type"), + "g_mdsft_pipeline": PropWithDefault("pipelineMode", "G_PM_NPRIMITIVE", "Pipeline Span Buffer Coherency"), +} +OTHERMODE_L_ATTRS = { + "g_mdsft_alpha_compare": PropWithDefault("alphaCompare", "G_AC_NONE", "Alpha Compare"), + "g_mdsft_zsrcsel": PropWithDefault("zSourceSelection", "G_ZS_PIXEL", "Z Source Selection"), +} -OTHERMODE_H_ATTRS = [ - PropWithDefault("alphaDither", "g_mdsft_alpha_dither", "G_AD_DISABLE"), - PropWithDefault("colorDither", "g_mdsft_rgb_dither", "G_CD_MAGICSQ"), - PropWithDefault("chromaKey", "g_mdsft_combkey", "G_CK_NONE"), - PropWithDefault("textureConvert", "g_mdsft_textconv", "G_TC_CONV"), - PropWithDefault("textureFilter", "g_mdsft_text_filt", "G_TF_POINT"), - PropWithDefault("lutFormat", "g_mdsft_textlut", "G_TT_NONE"), - PropWithDefault("textureLoD", "g_mdsft_textlod", "G_TL_TILE"), - PropWithDefault("textureDetail", "g_mdsft_textdetail", "G_TD_CLAMP"), - PropWithDefault("perspectiveCorrection", "g_mdsft_textpersp", "G_TP_NONE"), - PropWithDefault("cycleType", "g_mdsft_cycletype", "G_CYC_1CYCLE"), - PropWithDefault("pipelineMode", "g_mdsft_pipeline", "G_PM_NPRIMITIVE"), -] - -OTHERMODE_L_ATTRS = [ - PropWithDefault("alphaCompare", "g_mdsft_alpha_compare", "G_AC_NONE"), - PropWithDefault("zSourceSelection", "g_mdsft_zsrcsel", "G_ZS_PIXEL"), -] +RENDERMODE_FLAG_ATTRS = { + "aa_en": PropWithDefault("aa", False), + "z_cmp": PropWithDefault("zTest", False), + "z_upd": PropWithDefault("zWrite", False), + "clr_on_cvg": PropWithDefault("colorOnCvg", False), + "alpha_cvg_sel": PropWithDefault("alphaOnCvg", False), + "cvg_x_alpha": PropWithDefault("mulCvgXAlpha", False), + "force_bl": PropWithDefault("forceBlend", False), + "im_rd": PropWithDefault("readFB", False), + "cvg_dst": PropWithDefault("cvgDst", "CVG_DST_CLAMP"), + "zmode": PropWithDefault("zMode", "ZMODE_OPA"), +} diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 937e3ff0c..0b8d9d4be 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -251,7 +251,7 @@ def get_output_method(material: bpy.types.Material) -> str: if settings.cvg_x_alpha: return "CLIP" if settings.force_bl and is_blender_equation_equal( - material, -1, "G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_MEM", "G_BL_1MA" + material.f3d_mat, -1, "G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_MEM", "G_BL_1MA" ): return "XLU" return "OPA" @@ -294,7 +294,7 @@ def getTmemMax(texFormat): # Necessary for UV half pixel offset (see 13.7.5.3) def isTexturePointSampled(material): f3dMat = material.f3d_mat - return f3dMat.rdp_settings.g_mdsft_text_filt == "G_TF_POINT" + return f3dMat.get_rdp_othermode("text_filt") == "G_TF_POINT" def F3DOrganizeLights(self, context): @@ -553,25 +553,13 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): icon="TRIA_DOWN" if dataHolder.menu_upper else "TRIA_RIGHT", ) if not useDropdown or dataHolder.menu_upper: - tex_conv = textlut = textlod = textdetail = mip_count = cycle_type = None + auto_modes = {} if isinstance(dataHolder, F3DMaterialProperty): - # TODO: proper auto mip count once we start using tex manager for preview and UI - tex_conv, textlut, textlod, textdetail, mip_count, cycle_type = dataHolder.get_all_auto_modes.values() - prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") - prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") - prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") - draw_forced(inputGroup, settings, "g_mdsft_textconv", tex_conv is not None, "Texture Convert", tex_conv) - prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") - draw_forced(inputGroup, settings, "g_mdsft_textlut", textlut is not None, "Texture LUT", textlut) - draw_forced(inputGroup, settings, "g_mdsft_textlod", textlod is not None, "Texture LOD", textlod) - if settings.g_mdsft_textlod == "G_TL_LOD" or textlod: - draw_forced( - inputGroup, settings, "num_textures_mipmapped", mip_count is not None, "Number of Mipmaps", mip_count - ) - draw_forced(inputGroup, settings, "g_mdsft_textdetail", textdetail is not None, "Texture Detail", textdetail) - prop_split(inputGroup, settings, "g_mdsft_textpersp", "Texture Perspective Correction") - draw_forced(inputGroup, settings, "g_mdsft_cycletype", cycle_type is not None, "Cycle Type", cycle_type) - prop_split(inputGroup, settings, "g_mdsft_pipeline", "Pipeline Span Buffer Coherency") + auto_modes = dataHolder.get_othermode_h(True, True) + + for attr, mode in OTHERMODE_H_ATTRS.items(): + auto = auto_modes.get(attr) + draw_forced(inputGroup, settings, attr, auto is not None, mode.name, auto) def ui_lower_mode(settings, dataHolder, layout: UILayout, useDropdown): @@ -1337,7 +1325,7 @@ def draw(self, context): row.operator(AddPresetF3D.bl_idname, text="", icon="ADD") row.operator(AddPresetF3D.bl_idname, text="", icon="REMOVE").remove_active = True - if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and f3dMat.cycletype == "G_CYC_2CYCLE": + if f3dMat.get_rdp_othermode("alpha_compare") == "G_AC_THRESHOLD" and f3dMat.cycletype == "G_CYC_2CYCLE": multilineLabel( layout.box(), "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" @@ -1996,7 +1984,7 @@ def toggle_texture_node_muting(material: Material, texIndex: int, isUsed: bool): if node_tex_color_conv and node_tex_color_conv.mute != shouldMute: node_tex_color_conv.mute = shouldMute - mute_3point = shouldMute or f3dMat.rdp_settings.g_mdsft_text_filt != "G_TF_BILERP" + mute_3point = shouldMute or f3dMat.get_rdp_othermode("text_filt") != "G_TF_BILERP" if node_3point and node_3point.mute != mute_3point: node_3point.mute = mute_3point @@ -2020,7 +2008,7 @@ def set_texture_nodes_settings( for texNode in iter_tex_nodes(node_tree, texIndex): if texNode.image is not texProperty.tex: texNode.image = texProperty.tex - texNode.interpolation = "Linear" if f3dMat.rdp_settings.g_mdsft_text_filt == "G_TF_AVERAGE" else "Closest" + texNode.interpolation = "Linear" if f3dMat.get_rdp_othermode("text_filt") == "G_TF_AVERAGE" else "Closest" if texSize: continue @@ -2234,8 +2222,8 @@ def update_tex_values_manual(material: Material, context, prop_path=None): if not prop_path or "tex1" in prop_path: update_tex_values_index(material, texProperty=f3dMat.tex1, texIndex=1, isUsed=tex1_used) - texture_inputs["3 Point"].default_value = int(f3dMat.rdp_settings.g_mdsft_text_filt == "G_TF_BILERP") - uv_basis.inputs["EnableOffset"].default_value = int(f3dMat.rdp_settings.g_mdsft_text_filt != "G_TF_POINT") + texture_inputs["3 Point"].default_value = int(f3dMat.get_rdp_othermode("text_filt") == "G_TF_BILERP") + uv_basis.inputs["EnableOffset"].default_value = int(f3dMat.get_rdp_othermode("text_filt") != "G_TF_POINT") set_texture_settings_node(material) @@ -3681,17 +3669,17 @@ def is_geo_mode_on(self, prop: str) -> bool: def does_blender_use_input(self, setting: str) -> bool: return any(input == setting for input in self.blend_inputs) - def attributes_to_dict(self, info: dict): + def attributes_to_dict(self, info: dict[str, PropWithDefault]): data = {} - for key, attr, default in info: + for attr, mode in info.items(): value = getattr(self, attr) - if value != default: - data[key] = value + if value != mode.default: + data[mode.dict_name] = value return data - def attributes_from_dict(self, data: dict, info: dict): - for key, attr, default in info: - setattr(self, attr, data.get(key, default)) + def attributes_from_dict(self, data: dict, info: dict[str, PropWithDefault]): + for attr, mode in info.items(): + setattr(self, attr, data.get(mode.dict_name, mode.default)) geo_mode_attributes = {**F3D_GEO_MODES, **F3DLX_GEO_MODES, **F3DEX3_GEO_MODES} @@ -3715,19 +3703,6 @@ def other_mode_h_to_dict(self, lut_format=None): def other_mode_h_from_dict(self, data: dict): self.attributes_from_dict(data, OTHERMODE_H_ATTRS) - rendermode_flag_attributes = [ - ("aa", "aa_en", False), - ("zTest", "z_cmp", False), - ("zWrite", "z_upd", False), - ("colorOnCvg", "clr_on_cvg", False), - ("alphaOnCvg", "alpha_cvg_sel", False), - ("mulCvgXAlpha", "cvg_x_alpha", False), - ("forceBlend", "force_bl", False), - ("readFB", "im_rd", False), - ("cvgDst", "cvg_dst", "CVG_DST_CLAMP"), - ("zMode", "zmode", "ZMODE_OPA"), - ] - def other_mode_l_to_dict(self): data = self.attributes_to_dict(OTHERMODE_L_ATTRS) if self.g_mdsft_zsrcsel == "G_ZS_PRIM": @@ -3746,7 +3721,7 @@ def other_mode_l_to_dict(self): } ) data["renderMode"] = { - "flags": self.attributes_to_dict(self.rendermode_flag_attributes), + "flags": self.attributes_to_dict(RENDERMODE_FLAG_ATTRS), "blender": blender_data, } else: @@ -3773,7 +3748,7 @@ def other_mode_l_from_dict(self, data: dict): "presets", [self.rendermode_preset_cycle_1, self.rendermode_preset_cycle_2] ) - self.attributes_from_dict(flags, self.rendermode_flag_attributes) + self.attributes_from_dict(flags, RENDERMODE_FLAG_ATTRS) color_attrs = ("blend_p", "blend_m") alpha_attrs = ("blend_a", "blend_b") for i, cycle in enumerate(blender * 2 if len(blender) == 1 else blender): @@ -3790,7 +3765,7 @@ def other_to_dict(self): data = {} if self.clip_ratio != 1.0: data["clipRatio"] = self.clip_ratio - if self.g_mdsft_textlod == "G_TL_LOD" and self.num_textures_mipmapped != 1: # TODO + if self.g_mdsft_textlod == "G_TL_LOD" and self.num_textures_mipmapped != 1: data["mipmapCount"] = self.num_textures_mipmapped return data @@ -4633,6 +4608,14 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) + def get_rdp_othermode(self, prop: str): + prop = f"g_mdsft_{prop}" + value = getattr(self.rdp_settings, prop, "NONE") + if value == "NONE": + settings: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults + value = getattr(settings, prop) + return value + def get_tex_combiner_use(self, cycle_type: str = None) -> dict[int, bool]: if cycle_type is None: cycle_type = self.cycletype @@ -4682,7 +4665,7 @@ def get_tlut_mode(self, only_auto=False, dont_raise=False): if len(tlut_modes) == 1: return list(tlut_modes)[0] elif len(tlut_modes) == 0 or dont_raise: - return None if only_auto else self.rdp_settings.g_mdsft_textlut + return None if only_auto else self.get_rdp_othermode("textlut") text = ( "Can't mix CI and non-CI textures." if "G_TT_NONE" in tlut_modes @@ -4720,7 +4703,7 @@ def gen_auto_mips(self) -> bool: def get_tex_lod(self, only_auto=False) -> bool: if self.gen_auto_mips: return "G_TL_LOD" - return None if only_auto else self.rdp_settings.g_mdsft_textlod + return None if only_auto else self.get_rdp_othermode("textlod") @property def textlod(self) -> bool: @@ -4729,7 +4712,7 @@ def textlod(self) -> bool: def get_tex_detail(self, only_auto=False) -> bool: if self.pseudo_format in {"IHQ"}: return "G_TD_DETAIL" - return None if only_auto else self.rdp_settings.g_mdsft_textdetail + return None if only_auto else self.get_rdp_othermode("textdetail") @property def textdetail(self) -> bool: @@ -4747,7 +4730,7 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | Non return "G_TC_FILT" yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) if len(fmts) == 1: - if self.rdp_settings.g_mdsft_text_filt == "G_TF_POINT": + if self.get_rdp_othermode("text_filt") == "G_TF_POINT": return "G_TC_CONV" if yuv_tex == 0 and not dont_raise: raise PluginError( @@ -4765,7 +4748,7 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | Non "Texture 0 is YUV and texture 1 is not YUV.\nCannot use G_TC_FILTCONV to bypass convert in texture 0." ) elif not fmts: - return None if only_auto else self.rdp_settings.g_mdsft_textconv + return None if only_auto else self.get_rdp_othermode("textconv") else: if dont_raise: return None @@ -4782,7 +4765,7 @@ def tex_convert(self): return self.get_tex_convert(dont_raise=True) def get_cycle_type(self, only_auto=False, dont_raise=False): - cur_cycle_type = self.rdp_settings.g_mdsft_cycletype + cur_cycle_type = self.get_rdp_othermode("cycletype") tex_use = self.get_tex_combiner_use(cur_cycle_type) if ( self.uses_mipmap @@ -4796,15 +4779,25 @@ def get_cycle_type(self, only_auto=False, dont_raise=False): def cycletype(self): return self.get_cycle_type(False, dont_raise=True) - @property - def get_all_auto_modes(self): + def get_num_textures_mipmapped(self, only_auto=False): + if self.gen_auto_mips: + return 2 + return None if only_auto else self.rdp_settings.num_textures_mipmapped + + def get_othermode_h(self, only_auto=False, dont_raise=False): return { - "g_mdsft_text_filt": self.get_tex_convert(True, dont_raise=True), - "g_mdsft_textlut": self.get_tlut_mode(True, dont_raise=True), - "g_mdsft_textlod": self.get_tex_lod(True), - "g_mdsft_textdetail": self.get_tex_detail(True), - "num_textures_mipmapped": 2 if self.gen_auto_mips else None, - "g_mdsft_cycletype": self.get_cycle_type(True, dont_raise=True), + "g_mdsft_textconv": self.get_tex_convert(only_auto, dont_raise=dont_raise), + "g_mdsft_textlut": self.get_tlut_mode(only_auto, dont_raise=dont_raise), + "g_mdsft_textlod": self.get_tex_lod(only_auto), + "g_mdsft_textdetail": self.get_tex_detail(only_auto), + "num_textures_mipmapped": self.get_num_textures_mipmapped(only_auto), + "g_mdsft_cycletype": self.get_cycle_type(only_auto, dont_raise=dont_raise), + "g_mdsft_alpha_dither": None if only_auto else self.get_rdp_othermode("alpha_dither"), + "g_mdsft_rgb_dither": None if only_auto else self.get_rdp_othermode("rgb_dither"), + "g_mdsft_combkey": None if only_auto else self.get_rdp_othermode("combkey"), + "g_mdsft_text_filt": None if only_auto else self.get_rdp_othermode("text_filt"), + "g_mdsft_textpersp": None if only_auto else self.get_rdp_othermode("textpersp"), + "g_mdsft_pipeline": None if only_auto else self.get_rdp_othermode("pipeline"), } def key(self) -> F3DMaterialHash: diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 7e0e23e9d..75871ea06 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1329,7 +1329,10 @@ def draw_forced( props = holder.bl_rna.properties[prop] if "Enum" in props.bl_rna.name: props: bpy.types.EnumProperty - value: str = next((item.name for item in props.enum_items if item.identifier == value), value) + enum_items = holder.__annotations__.get(prop).keywords.get("items") + if isinstance(enum_items, Callable): + enum_items = enum_items(holder, bpy.context) + value: str = next((item[1] for item in enum_items if item[0] == value), value) prop_size_label(right_row, text=str(value)) else: right_row.prop( From 87a0b904b105a99e3d54f94952819062d66b72b1 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 17 May 2025 11:20:13 +0100 Subject: [PATCH 15/32] fix typo (pt keyboard moment) --- fast64_internal/f3d/f3d_enums.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 143478038..60bbcc151 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -152,7 +152,7 @@ DO_NOT_SET = ( "NONE", - "Don´t Set", + "Don't Set", "In write different this means not attempting to set, in write all it means fetching the world default", "X", ) From ba800b2cab6d7d8081c1cd004c4534b9084a1708 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 17 May 2025 11:23:52 +0100 Subject: [PATCH 16/32] check for tex1 instead of multitex --- fast64_internal/f3d/f3d_material.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 0b8d9d4be..df650b30f 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -4770,7 +4770,7 @@ def get_cycle_type(self, only_auto=False, dont_raise=False): if ( self.uses_mipmap or (self.get_tex_convert(dont_raise=dont_raise, tex_use=tex_use) == "G_TC_FILTCONV") - or self.check_multi_tex(tex_use) + or combiner_uses_tex1(self, cur_cycle_type) ): return "G_CYC_2CYCLE" return None if only_auto else cur_cycle_type From 920170589df85371abc4cbdcba2c25cb5ebb54af Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 17 May 2025 11:28:52 +0100 Subject: [PATCH 17/32] texture tab --- fast64_internal/f3d/f3d_material.py | 41 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index df650b30f..8931fd18a 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -1130,27 +1130,25 @@ def draw_textures( textures = f3d_mat.set_textures if is_simple else f3d_mat.used_textures col = layout.column() if len(textures) > 0: - col.label(text="Textures", icon="IMAGE_DATA") - - pseudo_split = col.split(factor=0.5) if f3d_mat.gen_pseudo_format else col - pseudo_split.prop(f3d_mat, "gen_pseudo_format") - if f3d_mat.gen_pseudo_format: - pseudo_split.prop(f3d_mat, "pseudo_format_internal", text="") - if f3d_mat.pseudo_fmt_can_mip: - mipmaps_split = col.split(factor=0.5) if f3d_mat.gen_auto_mips else col - draw_forced( - mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, name=None, split=False - ) - if f3d_mat.gen_auto_mips: - mipmaps_split.prop(f3d_mat, "auto_mipmaps", text="") - - self.ui_large(f3d_mat, col) - self.ui_scale(f3d_mat, col) - if len(textures) > 1: - col.prop(f3d_mat, "uv_basis", text="UV Basis") - # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that - self.draw_ci_warnings(col, f3d_mat) - col.separator(factor=1.0) + draw_and_check_tab(col, f3d_mat, "texture_tab", "Textures", "IMAGE_DATA") + if not f3d_mat.texture_tab: + return + pseudo_split = col.split(factor=0.5) if f3d_mat.gen_pseudo_format else col + pseudo_split.prop(f3d_mat, "gen_pseudo_format") + if f3d_mat.gen_pseudo_format: + pseudo_split.prop(f3d_mat, "pseudo_format_internal", text="") + if f3d_mat.pseudo_fmt_can_mip: + mipmaps_split = col.split(factor=0.5) if f3d_mat.gen_auto_mips else col + draw_forced(mipmaps_split, f3d_mat, "gen_auto_mips_internal", f3d_mat.forced_mipmap, name=None, split=False) + if f3d_mat.gen_auto_mips: + mipmaps_split.prop(f3d_mat, "auto_mipmaps", text="") + + self.ui_large(f3d_mat, col) + self.ui_scale(f3d_mat, col) + if len(textures) > 1: + col.prop(f3d_mat, "uv_basis", text="UV Basis") + # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that + self.draw_ci_warnings(col, f3d_mat) if f3d_mat.gen_auto_mips or f3d_mat.gen_pseudo_format: ui_image( f3d_mat.use_large_textures, @@ -4292,6 +4290,7 @@ class F3DMaterialProperty(PropertyGroup): UVanim0: bpy.props.PointerProperty(type=ProcAnimVectorProperty) # material textures + texture_tab: bpy.props.BoolProperty(name="Textures", update=update_tex_values) gen_pseudo_format: bpy.props.BoolProperty(name="Pseudo Formats", update=update_tex_values) pseudo_format_internal: bpy.props.EnumProperty( name="Pseudo Formats", From d701bfe31ee77f5836eb63021f5af62cb59e04f5 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 17 May 2025 12:36:18 +0100 Subject: [PATCH 18/32] first iter of placeholder under rdpq --- fast64_internal/f3d/f3d_gbi.py | 1 + fast64_internal/f3d/f3d_material.py | 54 ++++++++++++++++++------- fast64_internal/sm64/sm64_f3d_writer.py | 4 +- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index f5815dc61..31bfa4dac 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -164,6 +164,7 @@ def __init__(self, F3D_VER): F3DLP_GBI = self.F3DLP_GBI = self.F3DEX_GBI self.F3D_OLD_GBI = not (F3DEX_GBI or F3DEX_GBI_2 or F3DEX_GBI_3) self.F3D_GBI = is_ucode_f3d(F3D_VER) + self.RDPQ = not self.F3D_GBI # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 8931fd18a..61ddcacda 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -32,6 +32,7 @@ from .f3d_enums import * from .f3d_gbi import ( + F3D, get_F3D_GBI, enumTexScroll, isUcodeF3DEX1, @@ -1127,6 +1128,7 @@ def draw_ci_warnings(self, layout: UILayout, f3d_mat: "F3DMaterialProperty"): def draw_textures( self, f3d_mat: "F3DMaterialProperty", material: bpy.types.Material, layout: UILayout, is_simple: bool ): + f3d = get_F3D_GBI() textures = f3d_mat.set_textures if is_simple else f3d_mat.used_textures col = layout.column() if len(textures) > 0: @@ -1157,6 +1159,7 @@ def draw_textures( f3d_mat.all_textures[0], "Base Texture", False, + f3d, always_load=True, forced_fmt=f3d_mat.gen_pseudo_format, ) @@ -1166,7 +1169,9 @@ def draw_textures( for i, (tex_index, tex) in enumerate(textures.items()): if tex.menu and i > 0: col.separator(factor=1.0) - ui_image(f3d_mat.use_large_textures, f3d_mat.is_multi_tex, col, tex, f"Texture {tex_index}", not is_simple) + ui_image( + f3d_mat.use_large_textures, f3d_mat.is_multi_tex, col, tex, f"Texture {tex_index}", not is_simple, f3d + ) if tex.menu or i == len(textures) - 1: col.separator(factor=1.0) @@ -2851,6 +2856,13 @@ class TextureProperty(PropertyGroup): name="Texture Reference", default="0x08000000", ) + placeholder_slot: bpy.props.IntProperty( + name="Placeholder Slot", + default=1, + min=1, + max=15, + description="Texture placeholder to load, equivalent to using a texture reference in F3D", + ) tex_reference_size: bpy.props.IntVectorProperty( name="Texture Reference Size", min=1, @@ -2958,6 +2970,7 @@ def key(self): self.use_tex_reference if texSet else None, self.use_pal_reference if texSet and isCI else None, self.tex_reference if texSet and useRef else None, + self.placeholder_slot if texSet and useRef else None, self.pal_reference if texSet and useRef and isCI else None, self.pal_reference_size if texSet and useRef and isCI else None, self.load_tex if texSet else None, @@ -2998,10 +3011,12 @@ def ui_image( tex_prop: TextureProperty, name: str, show_toggle: bool, + f3d: F3D, hide_lowhigh=False, always_load=False, forced_fmt=False, ): + is_rdpq = f3d.RDPQ inputGroup = layout.column() row = inputGroup.row() @@ -3014,15 +3029,23 @@ def ui_image( width, height = tex_prop.size prop_input = inputGroup.column() + if is_rdpq: + row = prop_input.row() + row.prop(tex_prop, "use_tex_reference", text="Placeholder") + if tex_prop.use_tex_reference: + row.prop(tex_prop, "placeholder_slot", text="") + flipbook = tex_prop.flipbook is not None and tex_prop.flipbook.enable row = prop_input.row() has_texture = tex_prop.has_texture or always_load + if not always_load: row.prop(tex_prop, "load_tex") if tex_prop.load_tex: - row.prop(tex_prop, "use_tex_reference") - if tex_prop.use_tex_reference: - prop_split(prop_input, tex_prop, "tex_reference", "Texture Reference") + if not is_rdpq: + row.prop(tex_prop, "use_tex_reference", text="Reference") + if tex_prop.use_tex_reference: + prop_split(prop_input, tex_prop, "tex_reference", "Texture Reference") else: prop_split(prop_input, tex_prop, "tex_index", "Texture Index") if not flipbook or has_texture or always_load: @@ -3036,9 +3059,10 @@ def ui_image( if has_texture: size = tex_prop.size prop_input.label(text=f"Size: {size[0]}x{size[1]}") - if not tex_prop.has_texture: + if has_texture: + prop_split(prop_input, tex_prop, "dithering_method", "Dithering Method") + else: prop_split(prop_input, tex_prop, "tex_reference_size", "Texture Size") - prop_split(prop_input, tex_prop, "dithering_method", "Dithering Method") if not forced_fmt: fmt_row = prop_input.row() @@ -3068,17 +3092,17 @@ def ui_image( row = prop_input.row() row.prop(tex_prop, "load_pal") if tex_prop.load_pal: - row.prop(tex_prop, "use_pal_reference") - if tex_prop.load_pal: - if tex_prop.use_pal_reference and tex_prop.load_pal: - prop_split(prop_input, tex_prop, "pal_reference", "Palette Reference") - if tex_prop.pal is None: - prop_split(prop_input, tex_prop, "pal_reference_size", "Palette Size") + if not is_rdpq: + row.prop(tex_prop, "use_pal_reference") + if tex_prop.use_pal_reference and tex_prop.load_pal: + prop_split(prop_input, tex_prop, "pal_reference", "Palette Reference") + if tex_prop.pal is None: + prop_split(prop_input, tex_prop, "pal_reference_size", "Palette Size") else: prop_split(prop_input, tex_prop, "pal_index", "Palette Index") - if not tex_prop.has_texture or not tex_prop.has_palette: + if (not tex_prop.has_palette and not is_rdpq) or not tex_prop.load_tex: prop_input.template_ID(tex_prop, "pal", new="image.new", open="image.open") - if tex_prop.has_texture: + if has_texture: if tex_prop.pal: multilineLabel( prop_input, @@ -4290,7 +4314,7 @@ class F3DMaterialProperty(PropertyGroup): UVanim0: bpy.props.PointerProperty(type=ProcAnimVectorProperty) # material textures - texture_tab: bpy.props.BoolProperty(name="Textures", update=update_tex_values) + texture_tab: bpy.props.BoolProperty(name="Textures", default=True) gen_pseudo_format: bpy.props.BoolProperty(name="Pseudo Formats", update=update_tex_values) pseudo_format_internal: bpy.props.EnumProperty( name="Pseudo Formats", diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index 75a784c48..bf6c6a168 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -876,7 +876,9 @@ def draw(self, context): infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][0] + ": ") infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][1] + ".") prop_split(col, context.scene, "TexRectName", "Name") - ui_image(False, False, col, context.scene.texrect, context.scene.TexRectName, False, hide_lowhigh=True) + ui_image( + False, False, col, context.scene.texrect, context.scene.TexRectName, False, get_F3D_GBI(), hide_lowhigh=True + ) col.operator(ExportTexRectDraw.bl_idname) From 091cf2ad2984c2f043c1d44d49456d2f015bdd8e Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 17 May 2025 12:59:43 +0100 Subject: [PATCH 19/32] fix some rdpq conditions --- fast64_internal/f3d/f3d_material.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 61ddcacda..c946343e1 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3029,17 +3029,16 @@ def ui_image( width, height = tex_prop.size prop_input = inputGroup.column() - if is_rdpq: - row = prop_input.row() - row.prop(tex_prop, "use_tex_reference", text="Placeholder") - if tex_prop.use_tex_reference: - row.prop(tex_prop, "placeholder_slot", text="") - flipbook = tex_prop.flipbook is not None and tex_prop.flipbook.enable - row = prop_input.row() has_texture = tex_prop.has_texture or always_load if not always_load: + if is_rdpq: + row = prop_input.row() + row.prop(tex_prop, "use_tex_reference", text="Placeholder") + if tex_prop.use_tex_reference: + row.prop(tex_prop, "placeholder_slot", text="") + row = prop_input.row() row.prop(tex_prop, "load_tex") if tex_prop.load_tex: if not is_rdpq: @@ -3100,7 +3099,9 @@ def ui_image( prop_split(prop_input, tex_prop, "pal_reference_size", "Palette Size") else: prop_split(prop_input, tex_prop, "pal_index", "Palette Index") - if (not tex_prop.has_palette and not is_rdpq) or not tex_prop.load_tex: + if (is_rdpq and (not tex_prop.load_tex or not tex_prop.load_pal)) or ( + not is_rdpq and not tex_prop.has_palette + ): prop_input.template_ID(tex_prop, "pal", new="image.new", open="image.open") if has_texture: if tex_prop.pal: From 3c89cec93dd0a7d9f986db1a6065808104773d94 Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 19 May 2025 15:34:18 +0100 Subject: [PATCH 20/32] New experimental tex param UI --- fast64_internal/f3d/f3d_material.py | 105 ++++++++++++++++------------ fast64_internal/utility.py | 4 +- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index c946343e1..366633465 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -1135,6 +1135,8 @@ def draw_textures( draw_and_check_tab(col, f3d_mat, "texture_tab", "Textures", "IMAGE_DATA") if not f3d_mat.texture_tab: return + else: + return pseudo_split = col.split(factor=0.5) if f3d_mat.gen_pseudo_format else col pseudo_split.prop(f3d_mat, "gen_pseudo_format") if f3d_mat.gen_pseudo_format: @@ -1151,11 +1153,12 @@ def draw_textures( col.prop(f3d_mat, "uv_basis", text="UV Basis") # TODO: in the future we should make a multitex manager for UI and preview (and cache it) and use the errors from that self.draw_ci_warnings(col, f3d_mat) + col.separator(factor=1.0) if f3d_mat.gen_auto_mips or f3d_mat.gen_pseudo_format: ui_image( f3d_mat.use_large_textures, f3d_mat.is_multi_tex, - col, + col.box(), f3d_mat.all_textures[0], "Base Texture", False, @@ -1170,7 +1173,13 @@ def draw_textures( if tex.menu and i > 0: col.separator(factor=1.0) ui_image( - f3d_mat.use_large_textures, f3d_mat.is_multi_tex, col, tex, f"Texture {tex_index}", not is_simple, f3d + f3d_mat.use_large_textures, + f3d_mat.is_multi_tex, + col.box(), + tex, + f"Texture {tex_index}", + not is_simple, + f3d, ) if tex.menu or i == len(textures) - 1: col.separator(factor=1.0) @@ -1887,23 +1896,19 @@ def set_texture_settings_node(material: Material): nodes = material.node_tree.nodes textureSettings: ShaderNodeGroup = nodes["TextureSettings"] - desired_group = bpy.data.node_groups["TextureSettings_Lite"] - if (material.f3d_mat.tex0.tex and not material.f3d_mat.tex0.autoprop) or ( - material.f3d_mat.tex1.tex and not material.f3d_mat.tex1.autoprop - ): - desired_group = bpy.data.node_groups["TextureSettings_Advanced"] + desired_group = bpy.data.node_groups["TextureSettings_Advanced"] if textureSettings.node_tree is not desired_group: textureSettings.node_tree = desired_group -def setAutoProp(fieldProperty, pixelLength): - fieldProperty.mask = log2iRoundUp(pixelLength) - fieldProperty.shift = 0 - fieldProperty.low = 0 - fieldProperty.high = pixelLength - if fieldProperty.clamp and fieldProperty.mirror: - fieldProperty.high *= 2 - fieldProperty.high -= 1 +def setAutoProp(field: "TextureFieldProperty", pixel_length: int): + field.mask = log2iRoundUp(pixel_length) + high = pixel_length + if field.clamp: + high *= field.repeats + high += field.low + high -= 1 + field.high = high def set_texture_size(self, tex_size, tex_index): @@ -2771,7 +2776,8 @@ class TextureFieldProperty(PropertyGroup): update=update_tex_field_prop, ) low: bpy.props.FloatProperty( - name="Low", + name="Translate", + description="Low", min=0, max=1023.75, update=update_tex_field_prop, @@ -2791,13 +2797,22 @@ class TextureFieldProperty(PropertyGroup): ) shift: bpy.props.IntProperty( name="Shift", + description="Shift", min=-5, max=10, update=update_tex_field_prop, ) + repeats: bpy.props.IntProperty( + name="Repeats", + description="Repeats", + default=1, + min=0, + max=2047, + update=update_tex_field_prop, + ) def key(self): - return (self.clamp, self.mirror, round(self.low * 4), round(self.high * 4), self.mask, self.shift) + return (self.clamp, self.mirror, round(self.low * 4), round(self.high * 4), self.mask, self.shift, self.repeats) class SetTileSizeScrollProperty(PropertyGroup): @@ -3120,8 +3135,7 @@ def ui_image( ) if not forced_fmt: prop_split(prop_input, tex_prop, "ci_format", name="CI Format") - if not always_load: - prop_input.separator(factor=0.5) + prop_input.separator(factor=0.5) if not isLarge: if width > 0 and height > 0: @@ -3145,33 +3159,32 @@ def ui_image( icon="ERROR", ) - texFieldSettings = prop_input.column() - clampSettings = texFieldSettings.row() - clampSettings.prop(tex_prop.S, "clamp", text="Clamp S") - clampSettings.prop(tex_prop.T, "clamp", text="Clamp T") - - mirrorSettings = texFieldSettings.row() - mirrorSettings.prop(tex_prop.S, "mirror", text="Mirror S") - mirrorSettings.prop(tex_prop.T, "mirror", text="Mirror T") - - prop_input.prop(tex_prop, "autoprop", text="Auto Set Other Properties") - if not tex_prop.autoprop: - mask = prop_input.row() - mask.prop(tex_prop.S, "mask", text="Mask S") - mask.prop(tex_prop.T, "mask", text="Mask T") - - shift = prop_input.row() - shift.prop(tex_prop.S, "shift", text="Shift S") - shift.prop(tex_prop.T, "shift", text="Shift T") - if hide_lowhigh: - return - low = prop_input.row() - low.prop(tex_prop.S, "low", text="S Low") - low.prop(tex_prop.T, "low", text="T Low") - - high = prop_input.row() - high.prop(tex_prop.S, "high", text="S High") - high.prop(tex_prop.T, "high", text="T High") + def draw_s_t_field(layout: UILayout, text: str, prop: str, field_text=False): + split = layout.split(factor=0.2) + split.label(text=text) + row = split.row(align=True) + row.prop(tex_prop.S, prop, text="S" if field_text else "", toggle=1) + row.prop(tex_prop.T, prop, text="T" if field_text else "", toggle=1) + + autoprop = tex_prop.autoprop or is_rdpq + draw_s_t_field(prop_input, "Mirror", "mirror", True) + draw_s_t_field(prop_input, "Clamp", "clamp", True) + repeat_split = prop_input.split(factor=0.2) + repeat_split.label(text="Repeats") + repeat_split_right = repeat_split.split(factor=0.5, align=True) + draw_forced(repeat_split_right, tex_prop.S, "repeats", not autoprop or tex_prop.S.clamp, "", "Infinite", False) + draw_forced(repeat_split_right, tex_prop.T, "repeats", not autoprop or tex_prop.T.clamp, "", "Infinite", False) + + if not hide_lowhigh: + draw_s_t_field(prop_input, "Translate", "low") + draw_s_t_field(prop_input, "Scale", "shift") + + if not is_rdpq: + prop_input.prop(tex_prop, "autoprop", text="Auto Set Other Properties") + if not tex_prop.autoprop: + draw_s_t_field(prop_input, "Mask", "mask") + if not hide_lowhigh: + draw_s_t_field(prop_input, "High", "high") class CombinerProperty(PropertyGroup): diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 75871ea06..8c567bccc 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1320,8 +1320,8 @@ def draw_forced( split=True, ): split_row = layout.split(factor=0.5) if split else layout.row(align=True) - left_row = split_row.row() - right_row = split_row.row() + left_row = split_row.row(align=True) + right_row = split_row.row(align=True) if forced or name or split: left_row.label(text="" if name is None else name, icon="LOCKED" if forced else "NONE") right_row.enabled = not forced From 03beddfdb60fddfb2fab419ed9585b9898746d5f Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 19 May 2025 15:38:07 +0100 Subject: [PATCH 21/32] improve naming and add description for dither --- fast64_internal/f3d/f3d_material.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 366633465..160acbb90 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2852,13 +2852,14 @@ class TextureProperty(PropertyGroup): update=update_tex_values, ) dithering_method: bpy.props.EnumProperty( - name="Dithering Method", + name="Dithering (Conversion)", items=[ ("NONE", "None", ""), ("RANDOM", "Random", ""), ("DITHERED", "Dithered", ""), - ("Floyd-Steinberg", "Floyd-Steinberg", ""), + ("FLOYD", "Floyd-Steinberg", "TODO in mksprite, but by far the best dithering method on n64"), ], + description="How the texture will be dithered when quantizing (reducing colors), this helps with color banding", ) tex_index: bpy.props.IntProperty( name="Texture Index", @@ -3074,7 +3075,7 @@ def ui_image( size = tex_prop.size prop_input.label(text=f"Size: {size[0]}x{size[1]}") if has_texture: - prop_split(prop_input, tex_prop, "dithering_method", "Dithering Method") + prop_split(prop_input, tex_prop, "dithering_method", "Dithering (Conversion)") else: prop_split(prop_input, tex_prop, "tex_reference_size", "Texture Size") @@ -3172,8 +3173,12 @@ def draw_s_t_field(layout: UILayout, text: str, prop: str, field_text=False): repeat_split = prop_input.split(factor=0.2) repeat_split.label(text="Repeats") repeat_split_right = repeat_split.split(factor=0.5, align=True) - draw_forced(repeat_split_right, tex_prop.S, "repeats", not autoprop or tex_prop.S.clamp, "", "Infinite", False) - draw_forced(repeat_split_right, tex_prop.T, "repeats", not autoprop or tex_prop.T.clamp, "", "Infinite", False) + draw_forced( + repeat_split_right, tex_prop.S, "repeats", not autoprop or tex_prop.S.clamp, "", "Infinite", False + ) + draw_forced( + repeat_split_right, tex_prop.T, "repeats", not autoprop or tex_prop.T.clamp, "", "Infinite", False + ) if not hide_lowhigh: draw_s_t_field(prop_input, "Translate", "low") From d10ce00b114785a4c3c857ae793993405a71991d Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 19 May 2025 15:39:20 +0100 Subject: [PATCH 22/32] on export (dragorn suggestion) --- fast64_internal/f3d/f3d_material.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 160acbb90..7991d8783 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2859,7 +2859,7 @@ class TextureProperty(PropertyGroup): ("DITHERED", "Dithered", ""), ("FLOYD", "Floyd-Steinberg", "TODO in mksprite, but by far the best dithering method on n64"), ], - description="How the texture will be dithered when quantizing (reducing colors), this helps with color banding", + description="How the texture will be dithered when quantizing (reducing colors) on export, this helps with color banding", ) tex_index: bpy.props.IntProperty( name="Texture Index", From 766860fa982b51ebfaa1648dd76d695e0bd6c5b9 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 11:45:50 +0100 Subject: [PATCH 23/32] seperate slot for pal --- fast64_internal/f3d/f3d_material.py | 35 +++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 7991d8783..b2fba9529 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2872,7 +2872,7 @@ class TextureProperty(PropertyGroup): name="Texture Reference", default="0x08000000", ) - placeholder_slot: bpy.props.IntProperty( + tex_placeholder_slot: bpy.props.IntProperty( name="Placeholder Slot", default=1, min=1, @@ -2898,6 +2898,13 @@ class TextureProperty(PropertyGroup): default=False, update=update_tex_values, ) + pal_placeholder_slot: bpy.props.IntProperty( + name="Placeholder Slot", + default=2, + min=1, + max=15, + description="Texture placeholder to load, equivalent to using a palette reference in F3D", + ) load_pal: bpy.props.BoolProperty( name="Load Palette", default=True, @@ -2986,8 +2993,9 @@ def key(self): self.use_tex_reference if texSet else None, self.use_pal_reference if texSet and isCI else None, self.tex_reference if texSet and useRef else None, - self.placeholder_slot if texSet and useRef else None, + self.tex_placeholder_slot if texSet and useRef else None, self.pal_reference if texSet and useRef and isCI else None, + self.pal_placeholder_slot if texSet and self.pal_reference else None, self.pal_reference_size if texSet and useRef and isCI else None, self.load_tex if texSet else None, self.load_pal if texSet and isCI else None, @@ -3049,15 +3057,15 @@ def ui_image( has_texture = tex_prop.has_texture or always_load if not always_load: - if is_rdpq: - row = prop_input.row() - row.prop(tex_prop, "use_tex_reference", text="Placeholder") - if tex_prop.use_tex_reference: - row.prop(tex_prop, "placeholder_slot", text="") row = prop_input.row() row.prop(tex_prop, "load_tex") if tex_prop.load_tex: - if not is_rdpq: + if is_rdpq: + row = prop_input.row() if tex_prop.use_tex_reference else row + row.prop(tex_prop, "use_tex_reference", text="Placeholder") + if tex_prop.use_tex_reference: + row.prop(tex_prop, "tex_placeholder_slot", text="") + else: row.prop(tex_prop, "use_tex_reference", text="Reference") if tex_prop.use_tex_reference: prop_split(prop_input, tex_prop, "tex_reference", "Texture Reference") @@ -3107,7 +3115,12 @@ def ui_image( row = prop_input.row() row.prop(tex_prop, "load_pal") if tex_prop.load_pal: - if not is_rdpq: + if is_rdpq: + row = prop_input.row() if tex_prop.use_pal_reference else row + row.prop(tex_prop, "use_pal_reference", text="Placeholder") + if tex_prop.use_pal_reference: + row.prop(tex_prop, "pal_placeholder_slot", text="") + else: row.prop(tex_prop, "use_pal_reference") if tex_prop.use_pal_reference and tex_prop.load_pal: prop_split(prop_input, tex_prop, "pal_reference", "Palette Reference") @@ -3115,9 +3128,7 @@ def ui_image( prop_split(prop_input, tex_prop, "pal_reference_size", "Palette Size") else: prop_split(prop_input, tex_prop, "pal_index", "Palette Index") - if (is_rdpq and (not tex_prop.load_tex or not tex_prop.load_pal)) or ( - not is_rdpq and not tex_prop.has_palette - ): + if not tex_prop.has_palette: prop_input.template_ID(tex_prop, "pal", new="image.new", open="image.open") if has_texture: if tex_prop.pal: From b817968576747c88b520d3dc5b54249b6b29e04b Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 11:48:26 +0100 Subject: [PATCH 24/32] add not --- fast64_internal/f3d/f3d_material.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index b2fba9529..50c8b6bf7 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3185,10 +3185,10 @@ def draw_s_t_field(layout: UILayout, text: str, prop: str, field_text=False): repeat_split.label(text="Repeats") repeat_split_right = repeat_split.split(factor=0.5, align=True) draw_forced( - repeat_split_right, tex_prop.S, "repeats", not autoprop or tex_prop.S.clamp, "", "Infinite", False + repeat_split_right, tex_prop.S, "repeats", not autoprop or not tex_prop.S.clamp, "", "Infinite", False ) draw_forced( - repeat_split_right, tex_prop.T, "repeats", not autoprop or tex_prop.T.clamp, "", "Infinite", False + repeat_split_right, tex_prop.T, "repeats", not autoprop or not tex_prop.T.clamp, "", "Infinite", False ) if not hide_lowhigh: From 7fb7086d2545b64da5748aa99f3ae490185d8540 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 11:50:10 +0100 Subject: [PATCH 25/32] respect rdpq in nodes --- fast64_internal/f3d/f3d_material.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 50c8b6bf7..a9f0f9f74 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -1925,13 +1925,14 @@ def trunc_10_2(val: float): def update_tex_values_field(self: Material, texProperty: "TextureProperty", tex_size: list[int], tex_index: int): + f3d = get_F3D_GBI() nodes = self.node_tree.nodes textureSettings: ShaderNodeGroup = nodes["TextureSettings"] inputs = textureSettings.inputs set_texture_size(self, tex_size, tex_index) - if texProperty.autoprop: + if texProperty.autoprop or f3d.RDPQ: setAutoProp(texProperty.S, tex_size[0]) setAutoProp(texProperty.T, tex_size[1]) From eee476078fafd86f90cba0428fafa323e541f5d2 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 11:55:15 +0100 Subject: [PATCH 26/32] ignored instead of infinite without autoprop --- fast64_internal/f3d/f3d_material.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index a9f0f9f74..732a11036 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3185,12 +3185,16 @@ def draw_s_t_field(layout: UILayout, text: str, prop: str, field_text=False): repeat_split = prop_input.split(factor=0.2) repeat_split.label(text="Repeats") repeat_split_right = repeat_split.split(factor=0.5, align=True) - draw_forced( - repeat_split_right, tex_prop.S, "repeats", not autoprop or not tex_prop.S.clamp, "", "Infinite", False - ) - draw_forced( - repeat_split_right, tex_prop.T, "repeats", not autoprop or not tex_prop.T.clamp, "", "Infinite", False - ) + for f in [tex_prop.S, tex_prop.T]: + draw_forced( + repeat_split_right, + f, + "repeats", + not autoprop or not f.clamp, + "", + "Infinite" if autoprop else "Ignored", + False, + ) if not hide_lowhigh: draw_s_t_field(prop_input, "Translate", "low") From 633eedc0e590879f3f93278fc5139e549dbb0b22 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 14:28:53 +0100 Subject: [PATCH 27/32] RendermodeBlender class --- fast64_internal/f3d/f3d_gbi.py | 71 ++++++++++++------------------- fast64_internal/f3d/f3d_writer.py | 45 ++++++-------------- 2 files changed, 39 insertions(+), 77 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 31bfa4dac..e5cb6e356 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3407,7 +3407,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 @@ -4341,6 +4341,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.cycle2)})" + + 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 @@ -4351,7 +4368,10 @@ class SPSetOtherMode(GbiMacro): def to_binary(self, f3d, segments): data = 0 for flag in self.flagList: - data |= getattr(f3d, str(flag), flag) + if hasattr(flag, "to_binary"): + data |= flag.to_binary(f3d) + else: + data |= getattr(f3d, str(flag), flag) cmd = getattr(f3d, str(self.cmd), self.cmd) sft = getattr(f3d, str(self.sft), self.sft) return gsSPSetOtherMode(cmd, sft, self.length, data, f3d) @@ -4571,36 +4591,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) @@ -4609,25 +4610,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 e1c16a54a..6cc6372c5 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1714,15 +1714,10 @@ def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaults, f3d): cmd.flagList.append(settings.g_mdsft_zsrcsel) if settings.set_rendermode: - flagList, blendList = getRenderModeFlagList(settings, fMaterial) + flagList, blender = 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] + ")", - ] - ) + if blender is not None: + cmd.flagList.append(blender) fMaterial.mat_only_DL.commands.append(cmd) @@ -1740,17 +1735,16 @@ def saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRen fMaterial.revert.commands.append(DPSetPrimDepth()) if settings.set_rendermode: - flagList, blendList = getRenderModeFlagList(settings, fMaterial) - renderModeSet = DPSetRenderMode(flagList, blendList) + flagList, blender = getRenderModeFlagList(settings, fMaterial) + renderModeSet = DPSetRenderMode(flagList, blender) fMaterial.mat_only_DL.commands.append(renderModeSet) if defaultRenderMode is not None: fMaterial.revert.commands.append(DPSetRenderMode(defaultRenderMode, None)) -def getRenderModeFlagList(settings, fMaterial): +def getRenderModeFlagList(settings, fMaterial) -> tuple[list[str], RendermodeBlender | None]: flagList = [] - blendList = None # cycle independent if not settings.rendermode_advanced_enabled: @@ -1766,29 +1760,13 @@ def getRenderModeFlagList(settings, fMaterial): if cycle2 not in [value[0] for value in enumRenderModesCycle2]: cycle2 = "G_RM_NOOP" flagList = [settings.rendermode_preset_cycle_1, cycle2] + return flagList, None else: + blender_cycle1 = (settings.blend_p1, settings.blend_a1, settings.blend_m1, settings.blend_b1) if settings.g_mdsft_cycletype == "G_CYC_2CYCLE": - blendList = [ - settings.blend_p1, - settings.blend_a1, - settings.blend_m1, - settings.blend_b1, - settings.blend_p2, - settings.blend_a2, - settings.blend_m2, - settings.blend_b2, - ] + blender_cycle2 = blender_cycle1 else: - blendList = [ - settings.blend_p1, - settings.blend_a1, - settings.blend_m1, - settings.blend_b1, - settings.blend_p1, - settings.blend_a1, - settings.blend_m1, - settings.blend_b1, - ] + blender_cycle2 = (settings.blend_p2, settings.blend_a2, settings.blend_m2, settings.blend_b2) if settings.aa_en: flagList.append("AA_EN") @@ -1811,7 +1789,8 @@ def getRenderModeFlagList(settings, fMaterial): if settings.force_bl: flagList.append("FORCE_BL") - return flagList, blendList + return flagList, RendermodeBlender(blender_cycle1, blender_cycle2) + def saveOtherDefinition(fMaterial, material, defaults): From 375fcb3aa4dfc6adc875f303eb23c0d491800e68 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 14:51:39 +0100 Subject: [PATCH 28/32] othermode do not set code impl --- fast64_internal/f3d/f3d_material.py | 59 ++++---- fast64_internal/f3d/f3d_writer.py | 189 ++++++++++++------------ fast64_internal/sm64/sm64_f3d_writer.py | 12 +- 3 files changed, 132 insertions(+), 128 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 732a11036..8aa28b4e8 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -556,7 +556,7 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): if not useDropdown or dataHolder.menu_upper: auto_modes = {} if isinstance(dataHolder, F3DMaterialProperty): - auto_modes = dataHolder.get_othermode_h(True, True) + auto_modes = dataHolder.get_auto_othermode_h(True) for attr, mode in OTHERMODE_H_ATTRS.items(): auto = auto_modes.get(attr) @@ -4666,12 +4666,13 @@ class F3DMaterialProperty(PropertyGroup): use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) - def get_rdp_othermode(self, prop: str): + def get_rdp_othermode(self, prop: str, rdp_defaults: RDPSettings = None) -> str: prop = f"g_mdsft_{prop}" value = getattr(self.rdp_settings, prop, "NONE") - if value == "NONE": - settings: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults - value = getattr(settings, prop) + if value == "NONE" or value == "": + if rdp_defaults is None: + rdp_defaults: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults + value = getattr(rdp_defaults, prop) return value def get_tex_combiner_use(self, cycle_type: str = None) -> dict[int, bool]: @@ -4716,14 +4717,14 @@ def check_multi_tex(self, tex_use: dict = None): def is_multi_tex(self): return self.check_multi_tex() - def get_tlut_mode(self, only_auto=False, dont_raise=False): + def get_tlut_mode(self, only_auto=False, dont_raise=False, rdp_defaults: RDPSettings = None): if self.pseudo_format in {"IHQ", "SHQ"}: return "G_TT_NONE" tlut_modes = set(tex.textlut for tex in self.set_textures.values()) if len(tlut_modes) == 1: return list(tlut_modes)[0] elif len(tlut_modes) == 0 or dont_raise: - return None if only_auto else self.get_rdp_othermode("textlut") + return None if only_auto else self.get_rdp_othermode("textlut", rdp_defaults) text = ( "Can't mix CI and non-CI textures." if "G_TT_NONE" in tlut_modes @@ -4758,19 +4759,19 @@ def forced_mipmap(self): def gen_auto_mips(self) -> bool: return self.pseudo_fmt_can_mip and (self.gen_auto_mips_internal or self.forced_mipmap) - def get_tex_lod(self, only_auto=False) -> bool: + def get_tex_lod(self, only_auto=False, rdp_defaults: RDPSettings = None) -> bool: if self.gen_auto_mips: return "G_TL_LOD" - return None if only_auto else self.get_rdp_othermode("textlod") + return None if only_auto else self.get_rdp_othermode("textlod", rdp_defaults) @property def textlod(self) -> bool: return self.get_tex_lod(False) - def get_tex_detail(self, only_auto=False) -> bool: + def get_tex_detail(self, only_auto=False, rdp_defaults: RDPSettings = None) -> bool: if self.pseudo_format in {"IHQ"}: return "G_TD_DETAIL" - return None if only_auto else self.get_rdp_othermode("textdetail") + return None if only_auto else self.get_rdp_othermode("textdetail", rdp_defaults) @property def textdetail(self) -> bool: @@ -4780,7 +4781,9 @@ def textdetail(self) -> bool: def uses_mipmap(self) -> bool: return self.textlod == "G_TL_LOD" - def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | None = None): + def get_tex_convert( + self, only_auto=False, dont_raise=False, tex_use: dict | None = None, rdp_defaults: RDPSettings = None + ): textures = self.get_set_textures(tex_use) fmts: set[str] = set(tex.tex_format for tex in textures.values()) has_yuv = "YUV16" in fmts @@ -4788,7 +4791,7 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | Non return "G_TC_FILT" yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) if len(fmts) == 1: - if self.get_rdp_othermode("text_filt") == "G_TF_POINT": + if self.get_rdp_othermode("text_filt", rdp_defaults) == "G_TF_POINT": return "G_TC_CONV" if yuv_tex == 0 and not dont_raise: raise PluginError( @@ -4806,7 +4809,7 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | Non "Texture 0 is YUV and texture 1 is not YUV.\nCannot use G_TC_FILTCONV to bypass convert in texture 0." ) elif not fmts: - return None if only_auto else self.get_rdp_othermode("textconv") + return None if only_auto else self.get_rdp_othermode("textconv", rdp_defaults) else: if dont_raise: return None @@ -4822,8 +4825,8 @@ def get_tex_convert(self, only_auto=False, dont_raise=False, tex_use: dict | Non def tex_convert(self): return self.get_tex_convert(dont_raise=True) - def get_cycle_type(self, only_auto=False, dont_raise=False): - cur_cycle_type = self.get_rdp_othermode("cycletype") + def get_cycle_type(self, only_auto=False, dont_raise=False, rdp_defaults: RDPSettings = None): + cur_cycle_type = self.get_rdp_othermode("cycletype", rdp_defaults) tex_use = self.get_tex_combiner_use(cur_cycle_type) if ( self.uses_mipmap @@ -4839,23 +4842,19 @@ def cycletype(self): def get_num_textures_mipmapped(self, only_auto=False): if self.gen_auto_mips: - return 2 + return 2 # TODO: figure out mipmap count here or in texture exports? return None if only_auto else self.rdp_settings.num_textures_mipmapped - def get_othermode_h(self, only_auto=False, dont_raise=False): + def get_auto_othermode_h(self, dont_raise=False, rdp_defaults: RDPSettings = None): + if rdp_defaults is None: + rdp_defaults: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults return { - "g_mdsft_textconv": self.get_tex_convert(only_auto, dont_raise=dont_raise), - "g_mdsft_textlut": self.get_tlut_mode(only_auto, dont_raise=dont_raise), - "g_mdsft_textlod": self.get_tex_lod(only_auto), - "g_mdsft_textdetail": self.get_tex_detail(only_auto), - "num_textures_mipmapped": self.get_num_textures_mipmapped(only_auto), - "g_mdsft_cycletype": self.get_cycle_type(only_auto, dont_raise=dont_raise), - "g_mdsft_alpha_dither": None if only_auto else self.get_rdp_othermode("alpha_dither"), - "g_mdsft_rgb_dither": None if only_auto else self.get_rdp_othermode("rgb_dither"), - "g_mdsft_combkey": None if only_auto else self.get_rdp_othermode("combkey"), - "g_mdsft_text_filt": None if only_auto else self.get_rdp_othermode("text_filt"), - "g_mdsft_textpersp": None if only_auto else self.get_rdp_othermode("textpersp"), - "g_mdsft_pipeline": None if only_auto else self.get_rdp_othermode("pipeline"), + "g_mdsft_textconv": self.get_tex_convert(True, dont_raise=dont_raise, rdp_defaults=rdp_defaults), + "g_mdsft_textlut": self.get_tlut_mode(True, dont_raise=dont_raise, rdp_defaults=rdp_defaults), + "g_mdsft_textlod": self.get_tex_lod(True, rdp_defaults), + "g_mdsft_textdetail": self.get_tex_detail(True, rdp_defaults), + "num_textures_mipmapped": self.get_num_textures_mipmapped(True), + "g_mdsft_cycletype": self.get_cycle_type(True, dont_raise=dont_raise, rdp_defaults=rdp_defaults), } def key(self) -> F3DMaterialHash: diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 6cc6372c5..0c8d4b210 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -7,7 +7,13 @@ from bpy.utils import register_class, unregister_class from .f3d_enums import * -from .f3d_material import all_combiner_uses, getMaterialScrollDimensions, isTexturePointSampled, RDPSettings +from .f3d_material import ( + all_combiner_uses, + getMaterialScrollDimensions, + isTexturePointSampled, + F3DMaterialProperty, + RDPSettings, +) from .f3d_texture_writer import MultitexManager, TileLoad, maybeSaveSingleLargeTextureSetup from .f3d_gbi import * from .f3d_bleed import BleedGraphics @@ -1434,15 +1440,8 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): defaultRM = fModel.getRenderMode(drawLayer) else: defaultRM = None - saveOtherModeHDefinition( - fMaterial, - f3dMat.rdp_settings, - f3dMat.get_tlut_mode(), - defaults, - fModel.matWriteMethod, - fModel.f3d, - ) - saveOtherModeLDefinition(fMaterial, f3dMat.rdp_settings, defaults, defaultRM, fModel.matWriteMethod, fModel.f3d) + save_othermode_h(fMaterial, f3dMat, defaults, fModel.matWriteMethod, fModel.f3d) + save_othermode_l(fMaterial, f3dMat, defaults, defaultRM, fModel.matWriteMethod, fModel.f3d) saveOtherDefinition(fMaterial, f3dMat, defaults) # Set scale @@ -1511,6 +1510,13 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): ] ) + rdp_settings = f3dMat.rdp_settings + if rdp_settings.g_mdsft_zsrcsel == "G_ZS_PRIM": + depth, default_depth = rdp_settings.prim_depth, defaults.prim_depth + fMaterial.mat_only_DL.commands.append(DPSetPrimDepth(z=depth.z, dz=depth.dz)) + if (depth.z, depth.dz) != (default_depth.z, default_depth.dz): + fMaterial.revert.commands.append(DPSetPrimDepth(default_depth.z, default_depth.dz)) + fModel.onMaterialCommandsBuilt(fMaterial, material, drawLayer) # End Display List @@ -1652,95 +1658,95 @@ def saveGeoModeDefinition(fMaterial, settings, defaults, matWriteMethod): fMaterial.revert.commands.append(SPSetGeometryMode(clearGeo.flagList)) -def saveModeSetting(fMaterial, value, defaultValue, cmdClass): - if value != defaultValue: - fMaterial.mat_only_DL.commands.append(cmdClass(value)) - fMaterial.revert.commands.append(cmdClass(defaultValue)) - - -def saveOtherModeHDefinition(fMaterial, settings, tlut, defaults, matWriteMethod, f3d): - if matWriteMethod == GfxMatWriteMethod.WriteAll: - saveOtherModeHDefinitionAll(fMaterial, settings, tlut, defaults, f3d) - elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - saveOtherModeHDefinitionIndividual(fMaterial, settings, tlut, defaults) - else: - raise PluginError("Unhandled material write method: " + str(matWriteMethod)) - - -def saveOtherModeHDefinitionAll(fMaterial, settings, tlut, defaults, f3d): # TODO - cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - f3d.F3D_OLD_GBI, []) - cmd.flagList.append(settings.g_mdsft_alpha_dither) - cmd.flagList.append(settings.g_mdsft_rgb_dither) - cmd.flagList.append(settings.g_mdsft_combkey) - cmd.flagList.append(settings.g_mdsft_textconv) - cmd.flagList.append(settings.g_mdsft_text_filt) - cmd.flagList.append(tlut) - cmd.flagList.append(settings.g_mdsft_textlod) - cmd.flagList.append(settings.g_mdsft_textdetail) - cmd.flagList.append(settings.g_mdsft_textpersp) - cmd.flagList.append(settings.g_mdsft_cycletype) - cmd.flagList.append(settings.g_mdsft_pipeline) - - fMaterial.mat_only_DL.commands.append(cmd) - - -def saveOtherModeHDefinitionIndividual(fMaterial, settings, tlut, defaults): # TODO - saveModeSetting(fMaterial, settings.g_mdsft_alpha_dither, defaults.g_mdsft_alpha_dither, DPSetAlphaDither) - saveModeSetting(fMaterial, settings.g_mdsft_rgb_dither, defaults.g_mdsft_rgb_dither, DPSetColorDither) - saveModeSetting(fMaterial, settings.g_mdsft_combkey, defaults.g_mdsft_combkey, DPSetCombineKey) - saveModeSetting(fMaterial, settings.g_mdsft_textconv, defaults.g_mdsft_textconv, DPSetTextureConvert) - saveModeSetting(fMaterial, settings.g_mdsft_text_filt, defaults.g_mdsft_text_filt, DPSetTextureFilter) - saveModeSetting(fMaterial, tlut, defaults.g_mdsft_textlut, DPSetTextureLUT) - saveModeSetting(fMaterial, settings.g_mdsft_textlod, defaults.g_mdsft_textlod, DPSetTextureLOD) - saveModeSetting(fMaterial, settings.g_mdsft_textdetail, defaults.g_mdsft_textdetail, DPSetTextureDetail) - saveModeSetting(fMaterial, settings.g_mdsft_textpersp, defaults.g_mdsft_textpersp, DPSetTexturePersp) - saveModeSetting(fMaterial, settings.g_mdsft_cycletype, defaults.g_mdsft_cycletype, DPSetCycleType) - saveModeSetting(fMaterial, settings.g_mdsft_pipeline, defaults.g_mdsft_pipeline, DPPipelineMode) - - -def saveOtherModeLDefinition(fMaterial, settings, defaults, defaultRenderMode, matWriteMethod, f3d): - if matWriteMethod == GfxMatWriteMethod.WriteAll: - saveOtherModeLDefinitionAll(fMaterial, settings, defaults, 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): - 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) - cmd.flagList.append(settings.g_mdsft_zsrcsel) +OTHERMODE_H_TO_CMD_MAP = { + "g_mdsft_textconv": DPSetTextureConvert, + "g_mdsft_textlut": DPSetTextureLUT, + "g_mdsft_textlod": DPSetTextureLOD, + "g_mdsft_textdetail": DPSetTextureDetail, + "g_mdsft_cycletype": DPSetCycleType, + "g_mdsft_alpha_dither": DPSetAlphaDither, + "g_mdsft_rgb_dither": DPSetColorDither, + "g_mdsft_combkey": DPSetCombineKey, + "g_mdsft_text_filt": DPSetTextureFilter, + "g_mdsft_textpersp": DPSetTexturePersp, + "g_mdsft_pipeline": DPPipelineMode, +} +OTHERMODE_L_TO_CMD_MAP = {"g_mdsft_alpha_compare": DPSetAlphaCompare, "g_mdsft_zsrcsel": DPSetDepthSource} - if settings.set_rendermode: - flagList, blender = getRenderModeFlagList(settings, fMaterial) - cmd.flagList.extend(flagList) - if blender is not None: - cmd.flagList.append(blender) +OTHERMODE_CMD_MAP = OTHERMODE_H_TO_CMD_MAP | OTHERMODE_L_TO_CMD_MAP - fMaterial.mat_only_DL.commands.append(cmd) - - if settings.g_mdsft_zsrcsel == "G_ZS_PRIM": - fMaterial.mat_only_DL.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) +def save_othermode( + f_mat: FMaterial, value: str, defaults: RDPSettings, key: str, auto_modes: dict[str, str | None] = None +): + auto_modes = auto_modes or {} + auto_value = auto_modes.get(key) + if auto_value is not None: + if auto_value is not None and auto_value == getattr(defaults, key, None): + value = None + else: + value = auto_value + if value: + cmd = OTHERMODE_CMD_MAP[key] + f_mat.mat_only_DL.commands.append(cmd(value)) + default_value = getattr(defaults, key, None) + if value != default_value: + f_mat.revert.commands.append(cmd(default_value)) -def saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRenderMode): - saveModeSetting(fMaterial, settings.g_mdsft_alpha_compare, defaults.g_mdsft_alpha_compare, DPSetAlphaCompare) - saveModeSetting(fMaterial, settings.g_mdsft_zsrcsel, defaults.g_mdsft_zsrcsel, DPSetDepthSource) +def save_othermode_h( + f_mat, f3d_mat: F3DMaterialProperty, defaults: RDPSettings, mat_write_method: GfxMatWriteMethod, f3d: F3D +): + auto_modes = f3d_mat.get_auto_othermode_h() + rdp_settings = f3d_mat.rdp_settings + if mat_write_method == GfxMatWriteMethod.WriteAll: + cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - f3d.F3D_OLD_GBI, []) + for key in OTHERMODE_H_TO_CMD_MAP: + cmd.flagList.append(f3d_mat.get_rdp_othermode(key, defaults) or auto_modes.get(key)) + f_mat.mat_only_DL.commands.append(cmd) + elif mat_write_method == GfxMatWriteMethod.WriteDifferingAndRevert: + for key, cmd in OTHERMODE_H_TO_CMD_MAP.items(): + save_othermode(f_mat, getattr(rdp_settings, key, None), defaults, key, auto_modes) + else: + raise NotImplementedError(f"Unhandled material write method: {mat_write_method}") - if settings.g_mdsft_zsrcsel == "G_ZS_PRIM": - fMaterial.mat_only_DL.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) - fMaterial.revert.commands.append(DPSetPrimDepth()) - if settings.set_rendermode: - flagList, blender = getRenderModeFlagList(settings, fMaterial) - renderModeSet = DPSetRenderMode(flagList, blender) +def save_othermode_l( + f_mat, + f3d_mat: F3DMaterialProperty, + defaults: RDPSettings, + default_rm: tuple[str, str], + mat_write_method: GfxMatWriteMethod, + f3d: F3D, +): + rdp_settings = f3d_mat.rdp_settings + if rdp_settings.set_rendermode: + flag_list, blender = getRenderModeFlagList(rdp_settings, f_mat) + if mat_write_method == GfxMatWriteMethod.WriteAll: + baseLength = 3 if not rdp_settings.set_rendermode else 32 + cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, baseLength - f3d.F3D_OLD_GBI, []) + for key in OTHERMODE_L_TO_CMD_MAP: + cmd.flagList.append(f3d_mat.get_rdp_othermode(key, defaults)) + if rdp_settings.set_rendermode: + cmd.flagList.extend(flag_list) + if blender is not None: + cmd.flagList.append(blender) + f_mat.mat_only_DL.commands.append(cmd) + elif mat_write_method == GfxMatWriteMethod.WriteDifferingAndRevert: + for key, cmd in OTHERMODE_L_TO_CMD_MAP.items(): + save_othermode(f_mat, getattr(rdp_settings, key, None), defaults, key) + + if rdp_settings.set_rendermode: + renderModeSet = DPSetRenderMode(flag_list, blender) + f_mat.mat_only_DL.commands.append(renderModeSet) + else: + raise NotImplementedError(f"Unhandled material write method: {mat_write_method}") - fMaterial.mat_only_DL.commands.append(renderModeSet) - if defaultRenderMode is not None: - fMaterial.revert.commands.append(DPSetRenderMode(defaultRenderMode, None)) + if default_rm is not None and ( + rdp_settings.rendermode_advanced_enabled + or [rdp_settings.rendermode_preset_cycle_1, rdp_settings.rendermode_preset_cycle_2] != default_rm + ): + f_mat.revert.commands.append(DPSetRenderMode(default_rm, None)) def getRenderModeFlagList(settings, fMaterial) -> tuple[list[str], RendermodeBlender | None]: @@ -1792,7 +1798,6 @@ def getRenderModeFlagList(settings, fMaterial) -> tuple[list[str], RendermodeBle return flagList, RendermodeBlender(blender_cycle1, blender_cycle2) - def saveOtherDefinition(fMaterial, material, defaults): settings = material.rdp_settings if settings.clip_ratio != defaults.clip_ratio: diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index bf6c6a168..1f22676d8 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -5,7 +5,7 @@ from mathutils import Matrix, Vector from bpy.utils import register_class, unregister_class from ..panels import SM64_Panel -from ..f3d.f3d_writer import exportF3DCommon, saveModeSetting +from ..f3d.f3d_writer import exportF3DCommon, save_othermode from ..f3d.f3d_texture_writer import TexInfo from ..f3d.f3d_material import ( TextureProperty, @@ -309,21 +309,21 @@ def exportTexRectCommon(texProp, name, convertTextureData): # use_copy_mode is based on dl_hud_img_begin and dl_hud_img_end if use_copy_mode: - saveModeSetting(fMaterial, "G_CYC_COPY", defaults.g_mdsft_cycletype, DPSetCycleType) + save_othermode(fMaterial, "G_CYC_COPY", defaults, "g_mdsft_cycletype") else: - saveModeSetting(fMaterial, "G_CYC_1CYCLE", defaults.g_mdsft_cycletype, DPSetCycleType) + save_othermode(fMaterial, "G_CYC_1CYCLE", defaults, "g_mdsft_cycletype") fMaterial.mat_only_DL.commands.append( DPSetCombineMode(*fTexRect.f3d.G_CC_DECALRGBA, *fTexRect.f3d.G_CC_DECALRGBA) ) fMaterial.revert.commands.append(DPSetCombineMode(*fTexRect.f3d.G_CC_SHADE, *fTexRect.f3d.G_CC_SHADE)) - saveModeSetting(fMaterial, "G_TP_NONE", defaults.g_mdsft_textpersp, DPSetTexturePersp) - saveModeSetting(fMaterial, "G_AC_THRESHOLD", defaults.g_mdsft_alpha_compare, DPSetAlphaCompare) + save_othermode(fMaterial, "G_TP_NONE", defaults, "g_mdsft_textpersp") + save_othermode(fMaterial, "G_AC_THRESHOLD", defaults, "g_mdsft_alpha_compare") fMaterial.mat_only_DL.commands.append(DPSetBlendColor(0xFF, 0xFF, 0xFF, 0xFF)) fMaterial.mat_only_DL.commands.append(DPSetRenderMode(["G_RM_AA_XLU_SURF", "G_RM_AA_XLU_SURF2"], None)) fMaterial.revert.commands.append(DPSetRenderMode(["G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"], None)) - saveModeSetting(fMaterial, texProp.textlut, defaults.g_mdsft_textlut, DPSetTextureLUT) + save_othermode(fMaterial, texProp.textlut, defaults, "g_mdsft_textlut") ti = TexInfo() ti.fromProp(texProp, index=0, ignore_tex_set=True) ti.materialless_setup() From fade1e6658e1fd8d1be22c85e2aae2c3cf37b378 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 15:02:58 +0100 Subject: [PATCH 29/32] fix num_textures_mipmapped --- fast64_internal/f3d/f3d_enums.py | 1 - fast64_internal/f3d/f3d_material.py | 6 +++++- fast64_internal/f3d/f3d_writer.py | 14 +++++--------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 60bbcc151..442514e07 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -600,7 +600,6 @@ class PropWithDefault(NamedTuple): "g_mdsft_textconv": PropWithDefault("textureConvert", "G_TC_CONV", "Texture Convert"), "g_mdsft_text_filt": PropWithDefault("textureFilter", "G_TF_POINT", "Texture Filter"), "g_mdsft_textlut": PropWithDefault("lutFormat", "G_TT_NONE", "Texture LUT"), - "num_textures_mipmapped": PropWithDefault("numTexturesMipmapped", 2, "Number of Mipmaps"), "g_mdsft_textlod": PropWithDefault("textureLoD", "G_TL_TILE", "Texture LoD"), "g_mdsft_textdetail": PropWithDefault("textureDetail", "G_TD_CLAMP", "Texture Detail"), "g_mdsft_textpersp": PropWithDefault("perspectiveCorrection", "G_TP_NONE", "Texture Perspective Correction"), diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 8aa28b4e8..7c9e95d29 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -554,13 +554,17 @@ def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): icon="TRIA_DOWN" if dataHolder.menu_upper else "TRIA_RIGHT", ) if not useDropdown or dataHolder.menu_upper: - auto_modes = {} + auto_modes, use_lod = {}, settings.num_textures_mipmapped if isinstance(dataHolder, F3DMaterialProperty): auto_modes = dataHolder.get_auto_othermode_h(True) + use_lod = dataHolder.uses_mipmap for attr, mode in OTHERMODE_H_ATTRS.items(): auto = auto_modes.get(attr) draw_forced(inputGroup, settings, attr, auto is not None, mode.name, auto) + if use_lod: + auto = auto_modes.get("num_textures_mipmapped") + draw_forced(inputGroup, settings, "num_textures_mipmapped", auto is not None, "Number of Mipmaps", auto) def ui_lower_mode(settings, dataHolder, layout: UILayout, useDropdown): diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 0c8d4b210..0736c5eb4 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1290,10 +1290,7 @@ def getTexDimensions(material): @wrap_func_with_error_message(lambda args: (f"In material '{args['material'].name}': ")) def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): print(f"Writing material {material.name}") - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material + f3dMat: F3DMaterialProperty = material.f3d_mat areaKey = fModel.global_data.getCurrentAreaKey(f3dMat) areaIndex = fModel.global_data.current_area_index @@ -1447,12 +1444,11 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): # Set scale s = int(min(round(f3dMat.tex_scale[0] * 0x10000), 0xFFFF)) t = int(min(round(f3dMat.tex_scale[1] * 0x10000), 0xFFFF)) - if f3dMat.rdp_settings.g_mdsft_textlod == "G_TL_LOD": - fMaterial.mat_only_DL.commands.append( - SPTexture(s, t, f3dMat.rdp_settings.num_textures_mipmapped - 1, fModel.f3d.G_TX_RENDERTILE, 1) - ) + if f3dMat.get_rdp_othermode("textlod") == "G_TL_LOD": + mip_count = f3dMat.rdp_settings.num_textures_mipmapped - 1 else: - fMaterial.mat_only_DL.commands.append(SPTexture(s, t, 0, fModel.f3d.G_TX_RENDERTILE, 1)) + mip_count = 0 + fMaterial.mat_only_DL.commands.append(SPTexture(s, t, mip_count, fModel.f3d.G_TX_RENDERTILE, 1)) # Write textures multitexManager.writeAll(material, fMaterial, fModel, convertTextureData) From 7bcb59f16a0daedb22891d0ac7e658a9eb61cfbf Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 15:07:21 +0100 Subject: [PATCH 30/32] fix repo settings --- fast64_internal/f3d/f3d_material.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 7c9e95d29..be26212cc 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3721,6 +3721,15 @@ def blend_inputs(self): yield from self.blend_color_inputs yield from self.blend_alpha_inputs + def get_rdp_othermode(self, prop: str, rdp_defaults: "RDPSettings" = None): + prop = f"g_mdsft_{prop}" + value = getattr(self, prop, "NONE") + if value == "NONE" or value == "": + if rdp_defaults is None: + rdp_defaults: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults + value = getattr(rdp_defaults, prop) + return value + def has_prop_in_ucode(self, prop: str) -> bool: return prop in geo_modes_in_ucode(bpy.context.scene.f3d_type).values() @@ -3826,7 +3835,7 @@ def other_to_dict(self): data = {} if self.clip_ratio != 1.0: data["clipRatio"] = self.clip_ratio - if self.g_mdsft_textlod == "G_TL_LOD" and self.num_textures_mipmapped != 1: + if self.get_rdp_othermode("textlod") == "G_TL_LOD" and self.num_textures_mipmapped != 1: data["mipmapCount"] = self.num_textures_mipmapped return data @@ -4671,13 +4680,7 @@ class F3DMaterialProperty(PropertyGroup): cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) def get_rdp_othermode(self, prop: str, rdp_defaults: RDPSettings = None) -> str: - prop = f"g_mdsft_{prop}" - value = getattr(self.rdp_settings, prop, "NONE") - if value == "NONE" or value == "": - if rdp_defaults is None: - rdp_defaults: RDPSettings = create_or_get_world(bpy.context.scene).rdp_defaults - value = getattr(rdp_defaults, prop) - return value + return self.rdp_settings.get_rdp_othermode(prop, rdp_defaults) def get_tex_combiner_use(self, cycle_type: str = None) -> dict[int, bool]: if cycle_type is None: From 180ad8b790568eb90f58c158762fa6d3dd95e22b Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 21 May 2025 21:18:51 +0100 Subject: [PATCH 31/32] write all in revert --- fast64_internal/f3d/f3d_writer.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 0736c5eb4..958d87cd2 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1719,8 +1719,9 @@ def save_othermode_l( if rdp_settings.set_rendermode: flag_list, blender = getRenderModeFlagList(rdp_settings, f_mat) if mat_write_method == GfxMatWriteMethod.WriteAll: - baseLength = 3 if not rdp_settings.set_rendermode else 32 - cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, baseLength - f3d.F3D_OLD_GBI, []) + cmd = SPSetOtherMode( + "G_SETOTHERMODE_L", 0, (3 if not rdp_settings.set_rendermode else 32) - f3d.F3D_OLD_GBI, [] + ) for key in OTHERMODE_L_TO_CMD_MAP: cmd.flagList.append(f3d_mat.get_rdp_othermode(key, defaults)) if rdp_settings.set_rendermode: @@ -1742,7 +1743,17 @@ def save_othermode_l( rdp_settings.rendermode_advanced_enabled or [rdp_settings.rendermode_preset_cycle_1, rdp_settings.rendermode_preset_cycle_2] != default_rm ): - f_mat.revert.commands.append(DPSetRenderMode(default_rm, None)) + if mat_write_method == GfxMatWriteMethod.WriteAll: + f_mat.mat_only_DL.commands.append( + SPSetOtherMode( + "G_SETOTHERMODE_L", + 0, + 32 - f3d.F3D_OLD_GBI, + {*default_rm, defaults.g_mdsft_alpha_compare, defaults.g_mdsft_zsrcsel}, + ) + ) + else: + f_mat.revert.commands.append(DPSetRenderMode(default_rm, None)) def getRenderModeFlagList(settings, fMaterial) -> tuple[list[str], RendermodeBlender | None]: From fb2a91e6f8997c290a2be4dfd8dac743fe307da0 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 1 Jun 2025 20:03:13 +0100 Subject: [PATCH 32/32] fix mode exports --- fast64_internal/f3d/f3d_material.py | 29 +++++++++++++++-------------- fast64_internal/f3d/f3d_writer.py | 8 ++++---- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index be26212cc..bee4f63ab 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -295,7 +295,7 @@ def getTmemMax(texFormat): # Necessary for UV half pixel offset (see 13.7.5.3) def isTexturePointSampled(material): f3dMat = material.f3d_mat - return f3dMat.get_rdp_othermode("text_filt") == "G_TF_POINT" + return f3dMat.get_rdp_othermode("g_mdsft_text_filt") == "G_TF_POINT" def F3DOrganizeLights(self, context): @@ -1341,7 +1341,7 @@ def draw(self, context): row.operator(AddPresetF3D.bl_idname, text="", icon="ADD") row.operator(AddPresetF3D.bl_idname, text="", icon="REMOVE").remove_active = True - if f3dMat.get_rdp_othermode("alpha_compare") == "G_AC_THRESHOLD" and f3dMat.cycletype == "G_CYC_2CYCLE": + if f3dMat.get_rdp_othermode("g_mdsft_alpha_compare") == "G_AC_THRESHOLD" and f3dMat.cycletype == "G_CYC_2CYCLE": multilineLabel( layout.box(), "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" @@ -1997,7 +1997,7 @@ def toggle_texture_node_muting(material: Material, texIndex: int, isUsed: bool): if node_tex_color_conv and node_tex_color_conv.mute != shouldMute: node_tex_color_conv.mute = shouldMute - mute_3point = shouldMute or f3dMat.get_rdp_othermode("text_filt") != "G_TF_BILERP" + mute_3point = shouldMute or f3dMat.get_rdp_othermode("g_mdsft_text_filt") != "G_TF_BILERP" if node_3point and node_3point.mute != mute_3point: node_3point.mute = mute_3point @@ -2021,7 +2021,9 @@ def set_texture_nodes_settings( for texNode in iter_tex_nodes(node_tree, texIndex): if texNode.image is not texProperty.tex: texNode.image = texProperty.tex - texNode.interpolation = "Linear" if f3dMat.get_rdp_othermode("text_filt") == "G_TF_AVERAGE" else "Closest" + texNode.interpolation = ( + "Linear" if f3dMat.get_rdp_othermode("g_mdsft_text_filt") == "G_TF_AVERAGE" else "Closest" + ) if texSize: continue @@ -2235,8 +2237,8 @@ def update_tex_values_manual(material: Material, context, prop_path=None): if not prop_path or "tex1" in prop_path: update_tex_values_index(material, texProperty=f3dMat.tex1, texIndex=1, isUsed=tex1_used) - texture_inputs["3 Point"].default_value = int(f3dMat.get_rdp_othermode("text_filt") == "G_TF_BILERP") - uv_basis.inputs["EnableOffset"].default_value = int(f3dMat.get_rdp_othermode("text_filt") != "G_TF_POINT") + texture_inputs["3 Point"].default_value = int(f3dMat.get_rdp_othermode("g_mdsft_text_filt") == "G_TF_BILERP") + uv_basis.inputs["EnableOffset"].default_value = int(f3dMat.get_rdp_othermode("g_mdsft_text_filt") != "G_TF_POINT") set_texture_settings_node(material) @@ -3722,7 +3724,6 @@ def blend_inputs(self): yield from self.blend_alpha_inputs def get_rdp_othermode(self, prop: str, rdp_defaults: "RDPSettings" = None): - prop = f"g_mdsft_{prop}" value = getattr(self, prop, "NONE") if value == "NONE" or value == "": if rdp_defaults is None: @@ -3835,7 +3836,7 @@ def other_to_dict(self): data = {} if self.clip_ratio != 1.0: data["clipRatio"] = self.clip_ratio - if self.get_rdp_othermode("textlod") == "G_TL_LOD" and self.num_textures_mipmapped != 1: + if self.get_rdp_othermode("g_mdsft_textlod") == "G_TL_LOD" and self.num_textures_mipmapped != 1: data["mipmapCount"] = self.num_textures_mipmapped return data @@ -4731,7 +4732,7 @@ def get_tlut_mode(self, only_auto=False, dont_raise=False, rdp_defaults: RDPSett if len(tlut_modes) == 1: return list(tlut_modes)[0] elif len(tlut_modes) == 0 or dont_raise: - return None if only_auto else self.get_rdp_othermode("textlut", rdp_defaults) + return None if only_auto else self.get_rdp_othermode("g_mdsft_textlut", rdp_defaults) text = ( "Can't mix CI and non-CI textures." if "G_TT_NONE" in tlut_modes @@ -4769,7 +4770,7 @@ def gen_auto_mips(self) -> bool: def get_tex_lod(self, only_auto=False, rdp_defaults: RDPSettings = None) -> bool: if self.gen_auto_mips: return "G_TL_LOD" - return None if only_auto else self.get_rdp_othermode("textlod", rdp_defaults) + return None if only_auto else self.get_rdp_othermode("g_mdsft_textlod", rdp_defaults) @property def textlod(self) -> bool: @@ -4778,7 +4779,7 @@ def textlod(self) -> bool: def get_tex_detail(self, only_auto=False, rdp_defaults: RDPSettings = None) -> bool: if self.pseudo_format in {"IHQ"}: return "G_TD_DETAIL" - return None if only_auto else self.get_rdp_othermode("textdetail", rdp_defaults) + return None if only_auto else self.get_rdp_othermode("g_mdsft_textdetail", rdp_defaults) @property def textdetail(self) -> bool: @@ -4798,7 +4799,7 @@ def get_tex_convert( return "G_TC_FILT" yuv_tex = next((i for i, tex in textures.items() if tex.tex_format == "YUV16"), -1) if len(fmts) == 1: - if self.get_rdp_othermode("text_filt", rdp_defaults) == "G_TF_POINT": + if self.get_rdp_othermode("g_mdsft_text_filt", rdp_defaults) == "G_TF_POINT": return "G_TC_CONV" if yuv_tex == 0 and not dont_raise: raise PluginError( @@ -4816,7 +4817,7 @@ def get_tex_convert( "Texture 0 is YUV and texture 1 is not YUV.\nCannot use G_TC_FILTCONV to bypass convert in texture 0." ) elif not fmts: - return None if only_auto else self.get_rdp_othermode("textconv", rdp_defaults) + return None if only_auto else self.get_rdp_othermode("g_mdsft_textconv", rdp_defaults) else: if dont_raise: return None @@ -4833,7 +4834,7 @@ def tex_convert(self): return self.get_tex_convert(dont_raise=True) def get_cycle_type(self, only_auto=False, dont_raise=False, rdp_defaults: RDPSettings = None): - cur_cycle_type = self.get_rdp_othermode("cycletype", rdp_defaults) + cur_cycle_type = self.get_rdp_othermode("g_mdsft_cycletype", rdp_defaults) tex_use = self.get_tex_combiner_use(cur_cycle_type) if ( self.uses_mipmap diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 4539104a7..2b03daf59 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1441,7 +1441,7 @@ def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): # Set scale s = int(min(round(f3dMat.tex_scale[0] * 0x10000), 0xFFFF)) t = int(min(round(f3dMat.tex_scale[1] * 0x10000), 0xFFFF)) - if f3dMat.get_rdp_othermode("textlod") == "G_TL_LOD": + if f3dMat.get_rdp_othermode("g_mdsft_textlod") == "G_TL_LOD": mip_count = f3dMat.rdp_settings.num_textures_mipmapped - 1 else: mip_count = 0 @@ -1663,9 +1663,9 @@ def save_othermode_h( auto_modes = f3d_mat.get_auto_othermode_h() rdp_settings = f3d_mat.rdp_settings if mat_write_method == GfxMatWriteMethod.WriteAll: - cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - f3d.F3D_OLD_GBI, []) + cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - f3d.F3D_OLD_GBI, set()) for key in OTHERMODE_H_TO_CMD_MAP: - cmd.flagList.append(f3d_mat.get_rdp_othermode(key, defaults) or auto_modes.get(key)) + cmd.flagList.add(f3d_mat.get_rdp_othermode(key, defaults) or auto_modes.get(key)) f_mat.mat_only_DL.commands.append(cmd) elif mat_write_method == GfxMatWriteMethod.WriteDifferingAndRevert: for key, cmd in OTHERMODE_H_TO_CMD_MAP.items(): @@ -1687,7 +1687,7 @@ def save_othermode_l( flag_list, blender = getRenderModeFlagList(rdp_settings, f_mat) if mat_write_method == GfxMatWriteMethod.WriteAll: length = (3 if not rdp_settings.set_rendermode else 32) - f3d.F3D_OLD_GBI - cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, length, []) + cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, length, set()) modes = set(f3d_mat.get_rdp_othermode(key, defaults) for key in OTHERMODE_L_TO_CMD_MAP) cmd.flagList.update(modes)