From 47b35e6907b59cd70fc00b6f6bc1840722922018 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 6 Jun 2024 19:12:27 +0100 Subject: [PATCH 01/82] add entry --- fast64_internal/f3d/f3d_enums.py | 1 + fast64_internal/f3d/f3d_gbi.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 993a87316..d133cdb64 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -385,6 +385,7 @@ ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT and MM"), ("F3DEX2.Rej/LX2.Rej", "F3DEX2.Rej/LX2.Rej", "Variant of F3DEX2 family using vertex rejection instead of clipping"), ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen"), + ("F3DZEX (AC)", "F3DZEX (AC)", "Microcode used in Animal Crossing, extended version of F3DZEX"), ] enumLargeEdges = [ diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 452cfcd82..06f82eae6 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -68,6 +68,7 @@ class GfxMatWriteMethod(enum.Enum): "F3DLX.Rej": (64, 32), "F3DLP.Rej": (80, 32), "F3DEX2/LX2": (32, 32), + "F3DZEX (AC)": (32, 32), "F3DEX2.Rej/LX2.Rej": (64, 64), "F3DEX3": (56, 56), } @@ -126,7 +127,7 @@ def isUcodeF3DEX1(F3D_VER: str) -> bool: def isUcodeF3DEX2(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2"} + return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DZEX (AC)"} def isUcodeF3DEX3(F3D_VER: str) -> bool: From 6cde935bfe2fe435f2f3b9e2b6578384ebeb4e11 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 6 Jun 2024 19:30:44 +0100 Subject: [PATCH 02/82] add (GC) --- 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 d133cdb64..002e48892 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -385,7 +385,7 @@ ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT and MM"), ("F3DEX2.Rej/LX2.Rej", "F3DEX2.Rej/LX2.Rej", "Variant of F3DEX2 family using vertex rejection instead of clipping"), ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen"), - ("F3DZEX (AC)", "F3DZEX (AC)", "Microcode used in Animal Crossing, extended version of F3DZEX"), + ("F3DZEX (AC)", "F3DZEX (AC)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX"), ] enumLargeEdges = [ From 68b670155c14b07749b25e8abcf4f4d23110c8de Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 10:59:56 +0100 Subject: [PATCH 03/82] implementing this is making me feel so confused --- fast64_internal/f3d/f3d_gbi.py | 136 ++++++++++++++++++++++++++++++ fast64_internal/f3d/f3d_writer.py | 8 +- 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 06f82eae6..b339b6c9c 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -144,6 +144,7 @@ def __init__(self, F3D_VER): F3DEX_GBI_3 = self.F3DEX_GBI_3 = isUcodeF3DEX3(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) + F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -187,6 +188,12 @@ def __init__(self, F3D_VER): self.G_TRIFAN = 0x09 self.G_LIGHTTORDP = 0x0A else: + if F3DZEX_AC_EXT: + self.G_TRIN = 0x09 + self.G_TRIN_INDEPEND = 0x0A + + self.G_VTX_MODE_5bit = 0x00 + self.G_VTX_MODE_7bit = 0x01 self.G_SPECIAL_1 = 0xD5 self.G_SPECIAL_2 = 0xD4 self.G_SPECIAL_3 = 0xD3 @@ -1780,6 +1787,10 @@ def _SHIFTL(value, amount, mask): return (int(value) & ((1 << mask) - 1)) << amount +def _SHIFTR(value, amount, mask): + return (int(value) >> amount) & ((1 << mask) - 1) + + MTX_SIZE = 64 VTX_SIZE = 16 GFX_SIZE = 8 @@ -3572,6 +3583,18 @@ def _gsSP1Triangle_w1f(v0, v1, v2, flag, f3d): return _SHIFTL((flag), 24, 8) | _SHIFTL((v0) * 10, 16, 8) | _SHIFTL((v1) * 10, 8, 8) | _SHIFTL((v2) * 10, 0, 8) +def gsSPNTriangles(n: int, f3d): + return _SHIFTL(G_TRIN_INDEPEND, 24, 8) | _SHIFTL(n - 1, 17, 7) + + +def gsSPNTriangleData1(v0: int, v1: int, v2: int, f3d): # 5 bits per vertex id (32) + return _SHIFTL(v2, 10, 5) | _SHIFTL(v1, 5, 5) | _SHIFTL(v0, 0, 5) + + +def gsSPNTriangleData2(v0: int, v1: int, v2: int, f3d): # 7 bits per vertex id (128) + return _SHIFTL(v2, 14, 7) | _SHIFTL(v1, 7, 7) | _SHIFTL(v0, 0, 7) + + def _gsSPLine3D_w1(v0, v1, wd): return _SHIFTL((v0) * 2, 16, 8) | _SHIFTL((v1) * 2, 8, 8) | _SHIFTL((wd), 0, 8) @@ -3682,6 +3705,119 @@ def to_binary(self, f3d, segments): return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") +@dataclass(unsafe_hash=True) +class SPNTrianglesInit_5b(GbiMacro): + n: int + v0: int + v1: int + v2: int + v3: int + v4: int + v5: int + v6: int + v7: int + v8: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + _SHIFTL(G_TRIN_INDEPEND, 24, 8) + | _SHIFTL(self.n - 1, 17, 7) + | _SHIFTL(gsSPNTriangleData1(self.v6, self.v7, self.v8, f3d), 2, 15) + | _SHIFTL(_SHIFTR(gsSPNTriangleData1(self.v3, self.v4, self.v5, f3d), 13, 2), 0, 2), + _SHIFTL(gsSPNTriangleData1(self.v3, self.v4, self.v5, f3d), 19, 13) + | _SHIFTL(gsSPNTriangleData1(self.v0, self.v1, self.v2, f3d), 4, 15) + | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), + ) + else: + raise PluginError("SPNTrianglesInit_5b only available in F3DZEX (AC).") + + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +@dataclass(unsafe_hash=True) +class SP5bitTriangles(GbiMacro): + v0: int + v1: int + v2: int + v3: int + v4: int + v5: int + v6: int + v7: int + v8: int + v9: int + v10: int + v11: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + _SHIFTL(gsSPNTriangleData1(self.v9, self.v10, self.v11, f3d), 17, 15) + | _SHIFTL(gsSPNTriangleData1(self.v6, self.v7, self.v8, f3d), 2, 15) + | _SHIFTL(_SHIFTR(gsSPNTriangleData1(self.v3, self.v4, self.v5, f3d), 13, 2), 0, 2), + _SHIFTL(gsSPNTriangleData1(self.v3, self.v4, self.v5, f3d), 19, 13) + | _SHIFTL(gsSPNTriangleData1(self.v0, self.v1, self.v2, f3d), 4, 15) + | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), + ) + else: + raise PluginError("SP5bitTriangles not available in F3DZEX (AC).") + + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +@dataclass(unsafe_hash=True) +class SPNTrianglesInit_7b(GbiMacro): + n: int + v0: int + v1: int + v2: int + v3: int + v4: int + v5: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + gsSPNTriangles(n), + ( + _SHIFTL(gsSPNTriangleData2(v3, v4, v5, f3d), 22, 21) + | _SHIFTL(gsSPNTriangleData2(v0, v1, v2, f3d), 1, 21) + | _SHIFTL(f3d.G_VTX_MODE_7bit, 0, 1) + ), + ) + else: + raise PluginError("SPNTrianglesInit_7b only available in F3DZEX (AC).") + + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +@dataclass(unsafe_hash=True) +class SP7bitTriangles(GbiMacro): + v0: int + v1: int + v2: int + v3: int + v4: int + v5: int + v6: int + v7: int + v8: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + result = ( # This is how the macro is implemented + (gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d) << 43) | + (gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d) << 22) | + (gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d) << 1) | + G_VTX_MODE_7bit + ) + else: + raise PluginError("SP7bitTriangles not available in F3DZEX (AC).") + + return result.to_bytes(8, "big") + + # F3DEX3 TODO: Encoding of _g*SP5Triangles commands (SPTriangleStrip, SPTriangleFan) # and support for these in export including tri reordering diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 333d40366..b6dbb82f9 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -996,9 +996,7 @@ def processGeometry(self): bufferStart = bufferEnd # Load triangles - triCmds = createTriangleCommands( - self.vertexBufferTriangles, self.vertBuffer, not self.triConverterInfo.f3d.F3D_OLD_GBI - ) + triCmds = createTriangleCommands(self.vertexBufferTriangles, self.vertBuffer, self.triConverterInfo) if not self.material.f3d_mat.use_cel_shading: self.triList.commands.extend(triCmds) else: @@ -1228,7 +1226,7 @@ def getLoopColor(loop: bpy.types.MeshLoop, mesh: bpy.types.Mesh) -> Vector: return mathutils.Vector((normalizedRGB[0], normalizedRGB[1], normalizedRGB[2], normalizedA)) -def createTriangleCommands(triangles, vertexBuffer, useSP2Triangle): +def createTriangleCommands(triangles, vertexBuffer, triConverterInfo): triangles = copy.deepcopy(triangles) commands = [] @@ -1239,7 +1237,7 @@ def getIndices(tri): while t < len(triangles): firstTriIndices = getIndices(triangles[t]) t += 1 - if useSP2Triangle and t < len(triangles): + if not triConverterInfo.f3d.F3D_OLD_GBI and t < len(triangles): commands.append(SP2Triangles(*firstTriIndices, 0, *getIndices(triangles[t]), 0)) t += 1 else: From 19a6efcd2d9cca344a707ca59cbc6928b9010353 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 11:20:49 +0100 Subject: [PATCH 04/82] fix this --- fast64_internal/f3d/f3d_gbi.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index b339b6c9c..fac53d091 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3766,6 +3766,7 @@ def to_binary(self, f3d, segments): return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") +# The 7b tri commands aren't split in the gbi? @dataclass(unsafe_hash=True) class SPNTrianglesInit_7b(GbiMacro): n: int @@ -3779,10 +3780,10 @@ class SPNTrianglesInit_7b(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: words = ( - gsSPNTriangles(n), + _SHIFTL(gsSPNTriangles(self.n, f3d), 0, 32), ( - _SHIFTL(gsSPNTriangleData2(v3, v4, v5, f3d), 22, 21) - | _SHIFTL(gsSPNTriangleData2(v0, v1, v2, f3d), 1, 21) + _SHIFTL(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 22, 21) + | _SHIFTL(gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d), 1, 21) | _SHIFTL(f3d.G_VTX_MODE_7bit, 0, 1) ), ) @@ -3806,11 +3807,11 @@ class SP7bitTriangles(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: - result = ( # This is how the macro is implemented - (gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d) << 43) | - (gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d) << 22) | - (gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d) << 1) | - G_VTX_MODE_7bit + result = ( # This is how the macro is implemented + (gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d) << 43) + | (gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d) << 22) + | (gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d) << 1) + | G_VTX_MODE_7bit ) else: raise PluginError("SP7bitTriangles not available in F3DZEX (AC).") From 9363ba5ad0043774361545523572f5be00a11117 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 11:29:37 +0100 Subject: [PATCH 05/82] should be correct now the decomp implementation just has a double word, but for consistency this is better --- fast64_internal/f3d/f3d_gbi.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index fac53d091..20d400078 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3807,16 +3807,21 @@ class SP7bitTriangles(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: - result = ( # This is how the macro is implemented - (gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d) << 43) - | (gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d) << 22) - | (gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d) << 1) - | G_VTX_MODE_7bit + words = ( + ( + _SHIFTL(gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d), 11, 21) + | _SHIFTR(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 21 - 10, 10) # Upper 10 bits + ), + ( + _SHIFTL(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 32 - 11, 11) # Lower 11 bits + | _SHIFTR(gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d), 1, 21) + | _SHIFTL(f3d.G_VTX_MODE_7bit, 0, 1) + ), ) else: raise PluginError("SP7bitTriangles not available in F3DZEX (AC).") - return result.to_bytes(8, "big") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") # F3DEX3 TODO: Encoding of _g*SP5Triangles commands (SPTriangleStrip, SPTriangleFan) From a838784e171b29ff112a03d0513b284b902b6b16 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 11:30:38 +0100 Subject: [PATCH 06/82] use f3d --- fast64_internal/f3d/f3d_gbi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 20d400078..b0665f7c1 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3584,7 +3584,7 @@ def _gsSP1Triangle_w1f(v0, v1, v2, flag, f3d): def gsSPNTriangles(n: int, f3d): - return _SHIFTL(G_TRIN_INDEPEND, 24, 8) | _SHIFTL(n - 1, 17, 7) + return _SHIFTL(f3d.G_TRIN_INDEPEND, 24, 8) | _SHIFTL(n - 1, 17, 7) def gsSPNTriangleData1(v0: int, v1: int, v2: int, f3d): # 5 bits per vertex id (32) @@ -3721,7 +3721,7 @@ class SPNTrianglesInit_5b(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: words = ( - _SHIFTL(G_TRIN_INDEPEND, 24, 8) + _SHIFTL(f3d.G_TRIN_INDEPEND, 24, 8) | _SHIFTL(self.n - 1, 17, 7) | _SHIFTL(gsSPNTriangleData1(self.v6, self.v7, self.v8, f3d), 2, 15) | _SHIFTL(_SHIFTR(gsSPNTriangleData1(self.v3, self.v4, self.v5, f3d), 13, 2), 0, 2), From 0ebb8c3945c69c7712e1e36c65b7f6efd8ecfa9b Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 12:28:28 +0100 Subject: [PATCH 07/82] triangle exporting --- fast64_internal/f3d/f3d_gbi.py | 4 ++-- fast64_internal/f3d/f3d_writer.py | 31 +++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index b0665f7c1..eb10889b7 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -144,7 +144,7 @@ def __init__(self, F3D_VER): F3DEX_GBI_3 = self.F3DEX_GBI_3 = isUcodeF3DEX3(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) - F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" + self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -188,7 +188,7 @@ def __init__(self, F3D_VER): self.G_TRIFAN = 0x09 self.G_LIGHTTORDP = 0x0A else: - if F3DZEX_AC_EXT: + if self.F3DZEX_AC_EXT: self.G_TRIN = 0x09 self.G_TRIN_INDEPEND = 0x0A diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index b6dbb82f9..7c262b08c 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1230,18 +1230,33 @@ def createTriangleCommands(triangles, vertexBuffer, triConverterInfo): triangles = copy.deepcopy(triangles) commands = [] - def getIndices(tri): - return [vertexBuffer.index(v) for v in tri] + def getIndices(*tris): + return [vertexBuffer.index(v) for tri in tris for v in tri] + + def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data to fill out the command + if len(triangles) - i >= n: + return getIndices(*triangles[i:i+n]) + indices = getIndices(*triangles[i:]) + while len(indices) < n * 3: + indices.extend((0, 0, 0)) + return indices t = 0 + if triConverterInfo.f3d.F3DZEX_AC_EXT: + commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, 0, 3))) + t += 3 + while t < len(triangles): + commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) + t += 4 + return commands + while t < len(triangles): - firstTriIndices = getIndices(triangles[t]) - t += 1 - if not triConverterInfo.f3d.F3D_OLD_GBI and t < len(triangles): - commands.append(SP2Triangles(*firstTriIndices, 0, *getIndices(triangles[t]), 0)) - t += 1 + if not triConverterInfo.f3d.F3D_OLD_GBI and t + 1 < len(triangles): + commands.append(SP2Triangles(*getIndices(triangles[t]), 0, *getIndices(triangles[t + 1]), 0)) + t += 2 else: - commands.append(SP1Triangle(*firstTriIndices, 0)) + commands.append(SP1Triangle(*getIndices(triangles[t]), 0)) + t += 1 return commands From b6ecff527b3dabdfbae81a66dc575207d3d87e33 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 12:43:02 +0100 Subject: [PATCH 08/82] geo modes definitions --- fast64_internal/f3d/f3d_gbi.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index eb10889b7..7cd9e17aa 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -343,6 +343,14 @@ def __init__(self, F3D_VER): self.G_LOD = 0x00100000 # NOT IMPLEMENTED if F3DEX_GBI or F3DLP_GBI: self.G_CLIPPING = 0x00800000 + if self.F3DZEX_AC_EXT: + self.G_LIGHTING_POSITIONAL = 0x400000 + self.G_DECAL_LEQUAL = 0x00000000 + self.G_DECAL_GEQUAL = 0x00000010 + self.G_DECAL_EQUAL = 0x00000020 + self.G_DECAL_ALWAYS = 0x00000030 + self.G_DECAL_SPECIAL = 0x00000040 + self.G_DECAL_ALL = self.G_DECAL_ALWAYS | self.G_DECAL_SPECIAL else: self.G_CLIPPING = 0x00000000 From e5a553892c0cb270029ffa5e88a4077d07c579f4 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 13:59:13 +0100 Subject: [PATCH 09/82] second attempt --- fast64_internal/f3d/f3d_writer.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 7c262b08c..ef9d9809e 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1243,11 +1243,19 @@ def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data t t = 0 if triConverterInfo.f3d.F3DZEX_AC_EXT: - commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, 0, 3))) - t += 3 + init_5b = False while t < len(triangles): - commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) - t += 4 + if init_5b and t + 3 < len(triangles): # If we already have an init command and there is at least 4 tris left + commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) + t += 4 + elif t + 2 < len(triangles): # If there is at least 3 tris left + commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, t, 3))) + init_5b = True + t += 3 + else: # If there is atleast 2 tris left + commands.append(SPNTrianglesInit_7b(len(triangles), *get_n_tris_indices(triangles, t, 2))) + t += 2 + init_5b = False return commands while t < len(triangles): From 0587a686db5579ee2438c5e8f290521833537c97 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 14:13:50 +0100 Subject: [PATCH 10/82] third attempt --- fast64_internal/f3d/f3d_writer.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index ef9d9809e..a432f01b6 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1243,19 +1243,20 @@ def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data t t = 0 if triConverterInfo.f3d.F3DZEX_AC_EXT: - init_5b = False - while t < len(triangles): - if init_5b and t + 3 < len(triangles): # If we already have an init command and there is at least 4 tris left - commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) - t += 4 - elif t + 2 < len(triangles): # If there is at least 3 tris left - commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, t, 3))) - init_5b = True - t += 3 - else: # If there is atleast 2 tris left - commands.append(SPNTrianglesInit_7b(len(triangles), *get_n_tris_indices(triangles, t, 2))) - t += 2 - init_5b = False + left = (len(triangles) - 3) % 4 + tri_5_bit_len = len(triangles) - left + if len(triangles) <= 2: + commands.append(SPNTrianglesInit_7b(len(triangles), *get_n_tris_indices(triangles, t, 2))) + return commands + commands.append(SPNTrianglesInit_5b(tri_5_bit_len, *get_n_tris_indices(triangles, t, 3))) + t += 3 + while t < tri_5_bit_len: + commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) + t += 4 + if left == 3: + commands.append(SPNTrianglesInit_5b(left, *get_n_tris_indices(triangles, t, 3))) + elif left > 0: + commands.append(SPNTrianglesInit_7b(left, *get_n_tris_indices(triangles, t, 2))) return commands while t < len(triangles): From e936216278bca7e1e52762088c1d67cd6647aed1 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 14:19:05 +0100 Subject: [PATCH 11/82] improve definition --- fast64_internal/f3d/f3d_gbi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 7cd9e17aa..c993c055a 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -144,7 +144,7 @@ def __init__(self, F3D_VER): F3DEX_GBI_3 = self.F3DEX_GBI_3 = isUcodeF3DEX3(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.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" + F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = (F3D_VER == "F3DZEX (AC)") # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -188,7 +188,7 @@ def __init__(self, F3D_VER): self.G_TRIFAN = 0x09 self.G_LIGHTTORDP = 0x0A else: - if self.F3DZEX_AC_EXT: + if F3DZEX_AC_EXT: self.G_TRIN = 0x09 self.G_TRIN_INDEPEND = 0x0A @@ -343,8 +343,7 @@ def __init__(self, F3D_VER): self.G_LOD = 0x00100000 # NOT IMPLEMENTED if F3DEX_GBI or F3DLP_GBI: self.G_CLIPPING = 0x00800000 - if self.F3DZEX_AC_EXT: - self.G_LIGHTING_POSITIONAL = 0x400000 + if F3DZEX_AC_EXT: self.G_DECAL_LEQUAL = 0x00000000 self.G_DECAL_GEQUAL = 0x00000010 self.G_DECAL_EQUAL = 0x00000020 @@ -363,7 +362,8 @@ def __init__(self, F3D_VER): self.G_LIGHTING_SPECULAR = 0x00002000 self.G_FRESNEL_COLOR = 0x00004000 self.G_FRESNEL_ALPHA = 0x00008000 - self.G_LIGHTING_POSITIONAL = 0x00400000 # Ignored, always on + if F3DZEX_AC_EXT or F3DEX_GBI_3: + self.G_LIGHTING_POSITIONAL = 0x00400000 self.allGeomModeFlags = { "G_ZBUFFER", From 45a11253f747494071828442e70b26450165695f Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 16:29:40 +0100 Subject: [PATCH 12/82] Implement geo modes and their parsing + added bleed support --- fast64_internal/f3d/f3d_bleed.py | 15 ++++++++------- fast64_internal/f3d/f3d_gbi.py | 17 +++++++++++++---- fast64_internal/f3d/f3d_material.py | 28 ++++++++++++++++++++++++++++ fast64_internal/f3d/f3d_parser.py | 17 +++++++++++++++++ fast64_internal/f3d/f3d_writer.py | 10 +++++++--- 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 20ad88c7c..8ab68690f 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -17,6 +17,10 @@ SPLine3D, SPLineW3D, SP2Triangles, + SPNTrianglesInit_5b, + SP5bitTriangles, + SPNTrianglesInit_7b, + SP7bitTriangles, SPCullDisplayList, SPSegment, SPBranchLessZraw, @@ -48,6 +52,7 @@ GbiMacro, ) +TRI_CMDS = [SP2Triangles, SP1Triangle, SPLine3D, SPLineW3D, SPNTrianglesInit_5b, SP5bitTriangles, SPNTrianglesInit_7b, SP7bitTriangles] class BleedGraphics: # bleed_state "enums" @@ -297,7 +302,7 @@ def inline_triGroup( # add in triangles cmd_list.commands.extend(tri_list.commands) # skinned meshes don't draw tris sometimes, use this opportunity to save a sync - tri_cmds = [c for c in tri_list.commands if type(c) == SP1Triangle or type(c) == SP2Triangles] + tri_cmds = [c for c in tri_list.commands if type(c) in TRI_CMDS] if tri_cmds: reset_cmd_dict[DPPipeSync] = DPPipeSync() [bleed_gfx_lists.add_reset_cmd(cmd, reset_cmd_dict) for cmd in bleed_gfx_lists.bled_mats] @@ -423,10 +428,6 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in SPViewport, SPDisplayList, SPBranchList, - SP1Triangle, - SPLine3D, - SPLineW3D, - SP2Triangles, SPCullDisplayList, SPSegment, SPBranchLessZraw, @@ -436,7 +437,7 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in DPLoadBlock, DPLoadTile, DPLoadTLUTCmd, - DPFullSync, + DPFullSync, *TRI_CMDS ]: return False @@ -507,7 +508,7 @@ def bleed_between_tris(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, for parse_cmd in cmd_list.commands: if parse_cmd is cmd: return tri_buffered - if type(parse_cmd) in [SP2Triangles, SP1Triangle, SPLine3D, SPLineW3D]: + if type(parse_cmd) in TRI_CMDS: tri_buffered = False continue if type(parse_cmd) in conflict_cmds: diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index c993c055a..aa7986248 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -144,7 +144,7 @@ def __init__(self, F3D_VER): F3DEX_GBI_3 = self.F3DEX_GBI_3 = isUcodeF3DEX3(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) - F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = (F3D_VER == "F3DZEX (AC)") + F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -347,7 +347,7 @@ def __init__(self, F3D_VER): self.G_DECAL_LEQUAL = 0x00000000 self.G_DECAL_GEQUAL = 0x00000010 self.G_DECAL_EQUAL = 0x00000020 - self.G_DECAL_ALWAYS = 0x00000030 + self.G_DECAL_ALWAYS = self.G_DECAL_GEQUAL | self.G_DECAL_LEQUAL self.G_DECAL_SPECIAL = 0x00000040 self.G_DECAL_ALL = self.G_DECAL_ALWAYS | self.G_DECAL_SPECIAL else: @@ -392,6 +392,15 @@ def __init__(self, F3D_VER): "G_FRESNEL_COLOR", "G_FRESNEL_ALPHA", } + elif F3DZEX_AC_EXT: + self.allGeomModeFlags |= { + "G_DECAL_LEQUAL", + "G_DECAL_GEQUAL", + "G_DECAL_EQUAL", + "G_DECAL_ALWAYS", + "G_DECAL_SPECIAL", + "G_DECAL_ALL", + } self.G_FOG_H = self.G_FOG / 0x10000 self.G_LIGHTING_H = self.G_LIGHTING / 0x10000 @@ -3818,10 +3827,10 @@ def to_binary(self, f3d, segments): words = ( ( _SHIFTL(gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d), 11, 21) - | _SHIFTR(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 21 - 10, 10) # Upper 10 bits + | _SHIFTR(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 21 - 10, 10) # Upper 10 bits ), ( - _SHIFTL(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 32 - 11, 11) # Lower 11 bits + _SHIFTL(gsSPNTriangleData2(self.v3, self.v4, self.v5, f3d), 32 - 11, 11) # Lower 11 bits | _SHIFTR(gsSPNTriangleData2(self.v0, self.v1, self.v2, f3d), 1, 21) | _SHIFTL(f3d.G_VTX_MODE_7bit, 0, 1) ), diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 60afedc8a..e02925a78 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -513,6 +513,12 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], elif blendWarnings and not shadeInBlender and settings.g_fog: c.label(text="Fog not used in rendermode / blender, can disable.", icon="INFO") + if bpy.context.scene.f3d_type == "F3DZEX (AC)": + c = indentGroup(inputGroup, "Decals:", True) + c.prop(settings, "g_decal_gequal") + c.prop(settings, "g_decal_equal") + c.prop(settings, "g_decal_special") + if isF3DEX3: c = indentGroup(inputGroup, "Attribute offsets:", True) c.prop(settings, "g_attroffset_st_enable") @@ -2999,6 +3005,25 @@ class RDPSettings(PropertyGroup): update=update_node_values_with_preset, description="F3DEX3: Enables offsets to vertex ST values, usually for UV scrolling", ) + # AC Decal Modes + g_decal_gequal: bpy.props.BoolProperty( + name="Greater or Equal", + default=False, + update=update_node_values_with_preset, + description="F3DZEX (AC): Render with a positive offset (closer to the camera) instead of the default negative offset", # TODO: Double check + ) + g_decal_equal: bpy.props.BoolProperty( + name="Equal", + default=False, + update=update_node_values_with_preset, + description="F3DZEX (AC): Render with no offset", # TODO: Double check + ) + g_decal_special: bpy.props.BoolProperty( + name="Special", + default=False, + update=update_node_values_with_preset, + description="F3DZEX (AC): ", # TODO: Write description + ) # v1/2 difference g_cull_front: bpy.props.BoolProperty( name="Cull Front", @@ -3323,6 +3348,9 @@ def key(self): return ( self.g_zbuffer, self.g_shade, + self.g_decal_gequal, + self.g_decal_equal, + self.g_decal_special, self.g_cull_front, self.g_cull_back, self.g_attroffset_st_enable, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 39039e806..3423e5f9a 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -895,6 +895,13 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_fresnel_color = value if bitFlags & self.f3d.G_FRESNEL_ALPHA: rdp_settings.g_fresnel_alpha = value + elif self.f3d.F3DZEX_AC_EXT: + if bitFlags & self.f3d.G_DECAL_GEQUAL: + rdp_settings.g_decal_gequal = value + if bitFlags & self.f3d.G_DECAL_EQUAL: + rdp_settings.g_decal_equal = value + if bitFlags & self.f3d.G_DECAL_SPECIAL: + rdp_settings.g_decal_special = value if bitFlags & self.f3d.G_FOG: rdp_settings.g_fog = value if bitFlags & self.f3d.G_LIGHTING: @@ -939,6 +946,15 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_lighting_specular = False rdp_settings.g_fresnel_color = False rdp_settings.g_fresnel_alpha = False + if self.f3d.F3DZEX_AC_EXT: + rdp_settings.g_gequal = bitFlags & self.f3d.G_DECAL_GEQUAL != 0 + rdp_settings.g_equal = bitFlags & self.f3d.G_DECAL_EQUAL != 0 + rdp_settings.g_decal_special = bitFlags & self.f3d.G_DECAL_SPECIAL != 0 + else: + rdp_settings.g_gequal = False + rdp_settings.g_equal = False + rdp_settings.g_decal_special = False + rdp_settings.g_fog = bitFlags & self.f3d.G_FOG != 0 rdp_settings.g_lighting = bitFlags & self.f3d.G_LIGHTING != 0 rdp_settings.g_tex_gen = bitFlags & self.f3d.G_TEXTURE_GEN != 0 @@ -1551,6 +1567,7 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr self.addTriangle(command.params[0:3], dlData) elif command.name == "gsSP2Triangles": self.addTriangle(command.params[0:3] + command.params[4:7], dlData) + # TODO: Parse Animal Crossing's F3DZEX extended 5/7 bit tri commands elif command.name == "gsSPDisplayList" or command.name.startswith("gsSPBranch"): newDLName = self.processDLName(command.params[0]) if newDLName is not None: diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index a432f01b6..9b71e7796 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1233,9 +1233,9 @@ def createTriangleCommands(triangles, vertexBuffer, triConverterInfo): def getIndices(*tris): return [vertexBuffer.index(v) for tri in tris for v in tri] - def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data to fill out the command + def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data to fill out the command if len(triangles) - i >= n: - return getIndices(*triangles[i:i+n]) + return getIndices(*triangles[i : i + n]) indices = getIndices(*triangles[i:]) while len(indices) < n * 3: indices.extend((0, 0, 0)) @@ -1251,7 +1251,7 @@ def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data t commands.append(SPNTrianglesInit_5b(tri_5_bit_len, *get_n_tris_indices(triangles, t, 3))) t += 3 while t < tri_5_bit_len: - commands.append(SP5bitTriangles( *get_n_tris_indices(triangles, t, 4))) + commands.append(SP5bitTriangles(*get_n_tris_indices(triangles, t, 4))) t += 4 if left == 3: commands.append(SPNTrianglesInit_5b(left, *get_n_tris_indices(triangles, t, 3))) @@ -1630,6 +1630,10 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_lighting_specular, defaults.g_lighting_specular, "G_LIGHTING_SPECULAR", *args) saveFunc(settings.g_fresnel_color, defaults.g_fresnel_color, "G_FRESNEL_COLOR", *args) saveFunc(settings.g_fresnel_alpha, defaults.g_fresnel_alpha, "G_FRESNEL_ALPHA", *args) + elif bpy.context.scene.f3d_type == "F3DZEX (AC)": + saveFunc(settings.g_decal_gequal, defaults.g_decal_gequal, "G_DECAL_GEQUAL", *args) + saveFunc(settings.g_decal_equal, defaults.g_decal_equal, "G_DECAL_EQUAL", *args) + saveFunc(settings.g_decal_special, defaults.g_decal_special, "G_DECAL_SPECIAL", *args) saveFunc(settings.g_fog, defaults.g_fog, "G_FOG", *args) saveFunc(settings.g_lighting, defaults.g_lighting, "G_LIGHTING", *args) saveFunc(settings.g_tex_gen, defaults.g_tex_gen, "G_TEXTURE_GEN", *args) From 98281e6c3feceb818c61c75c1520f842d1b7d30d Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 18:35:32 +0100 Subject: [PATCH 13/82] point lit geo mode --- fast64_internal/f3d/f3d_gbi.py | 10 ++++++---- fast64_internal/f3d/f3d_material.py | 15 ++++++++++++--- fast64_internal/f3d/f3d_parser.py | 4 ++++ fast64_internal/f3d/f3d_writer.py | 2 ++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index aa7986248..c9c1d52a8 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -132,7 +132,8 @@ def isUcodeF3DEX2(F3D_VER: str) -> bool: def isUcodeF3DEX3(F3D_VER: str) -> bool: return F3D_VER == "F3DEX3" - +def isUcodePointLit(F3D_VER: str) -> bool: + return F3D_VER == {"F3DEX3", "F3DZEX (AC)"} class F3D: """NOTE: do not initialize this class manually! use get_F3D_GBI so that the single instance is cached from the microcode type.""" @@ -145,6 +146,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) F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" + F3D_POINT_LIT = self.F3D_POINT_LIT = F3D_VER == isUcodePointLit(F3D_VER) # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -362,8 +364,6 @@ def __init__(self, F3D_VER): self.G_LIGHTING_SPECULAR = 0x00002000 self.G_FRESNEL_COLOR = 0x00004000 self.G_FRESNEL_ALPHA = 0x00008000 - if F3DZEX_AC_EXT or F3DEX_GBI_3: - self.G_LIGHTING_POSITIONAL = 0x00400000 self.allGeomModeFlags = { "G_ZBUFFER", @@ -378,7 +378,6 @@ def __init__(self, F3D_VER): "G_TEXTURE_GEN_LINEAR", "G_LOD", "G_SHADING_SMOOTH", - "G_LIGHTING_POSITIONAL", "G_CLIPPING", } if F3DEX_GBI_3: @@ -401,6 +400,9 @@ def __init__(self, F3D_VER): "G_DECAL_SPECIAL", "G_DECAL_ALL", } + if F3D_POINT_LIT: + self.G_LIGHTING_POSITIONAL = 0x00400000 + self.allGeomModeFlags.add("G_LIGHTING_POSITIONAL") self.G_FOG_H = self.G_FOG / 0x10000 self.G_LIGHTING_H = self.G_LIGHTING / 0x10000 diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index e02925a78..39ef1ee93 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -441,6 +441,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], return c isF3DEX3 = bpy.context.scene.f3d_type == "F3DEX3" + isF3DZEX_AC = bpy.context.scene.f3d_type == "F3DZEX (AC)" lightFxPrereq = isF3DEX3 and settings.g_lighting ccWarnings = shadeInCC = False blendWarnings = shadeInBlender = zInBlender = False @@ -459,6 +460,8 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if c is not None: if ccWarnings and not shadeInCC and not settings.g_tex_gen: c.label(text="Shade not used in CC, can disable lighting.", icon="INFO") + if isF3DZEX_AC: + c.prop(settings, "g_lighting_positional") if isF3DEX3: c.prop(settings, "g_packed_normals") c.prop(settings, "g_lighting_specular") @@ -513,13 +516,12 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], elif blendWarnings and not shadeInBlender and settings.g_fog: c.label(text="Fog not used in rendermode / blender, can disable.", icon="INFO") - if bpy.context.scene.f3d_type == "F3DZEX (AC)": + if isF3DZEX_AC: c = indentGroup(inputGroup, "Decals:", True) c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_equal") c.prop(settings, "g_decal_special") - - if isF3DEX3: + elif isF3DEX3: c = indentGroup(inputGroup, "Attribute offsets:", True) c.prop(settings, "g_attroffset_st_enable") c.prop(settings, "g_attroffset_z_enable") @@ -3110,6 +3112,12 @@ class RDPSettings(PropertyGroup): update=update_node_values_with_preset, description="F3DEX1/LX only, exact function unknown", ) + g_lighting_positional: bpy.props.BoolProperty( + name="Positional Lighting", + default=False, # TODO: Check with sauren that this should be defaulted to false + update=update_node_values_with_preset, + description="F3DZEX (AC): Enables positional lights", + ) # upper half mode # v2 only @@ -3365,6 +3373,7 @@ def key(self): self.g_lod, self.g_shade_smooth, self.g_clipping, + self.g_lighting_positional, self.g_mdsft_alpha_dither, self.g_mdsft_rgb_dither, self.g_mdsft_combkey, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 3423e5f9a..d61691c4b 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -916,6 +916,8 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_shade_smooth = value if bitFlags & self.f3d.G_CLIPPING: rdp_settings.g_clipping = value + if bitFlags & self.f3d.G_LIGHTING_POSITIONAL: + rdp_settings.g_lighting_positional = value def loadGeoFlags(self, command: "ParsedMacro"): mat = self.mat() @@ -962,6 +964,8 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_lod = bitFlags & self.f3d.G_LOD != 0 rdp_settings.g_shade_smooth = bitFlags & self.f3d.G_SHADING_SMOOTH != 0 rdp_settings.g_clipping = bitFlags & self.f3d.G_CLIPPING != 0 + if self.f3d.F3D_POINT_LIT: + rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 def setCombineLerp(self, lerp0, lerp1): mat = self.mat() diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 9b71e7796..9e5b76298 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1642,6 +1642,8 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", *args) if isUcodeF3DEX1(bpy.context.scene.f3d_type): saveFunc(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", *args) + if isUcodePointLit(bpy.context.scene.f3d_type): + saveFunc(settings.g_lighting_positional, defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", *args) def saveGeoModeDefinitionF3DEX2(fMaterial, settings, defaults, matWriteMethod): From 6fbbed05c54f14f351e3d87e5fe46bfadc40b1c4 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 18:35:58 +0100 Subject: [PATCH 14/82] black formatting --- fast64_internal/f3d/f3d_bleed.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 8ab68690f..815f1d349 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -52,7 +52,17 @@ GbiMacro, ) -TRI_CMDS = [SP2Triangles, SP1Triangle, SPLine3D, SPLineW3D, SPNTrianglesInit_5b, SP5bitTriangles, SPNTrianglesInit_7b, SP7bitTriangles] +TRI_CMDS = [ + SP2Triangles, + SP1Triangle, + SPLine3D, + SPLineW3D, + SPNTrianglesInit_5b, + SP5bitTriangles, + SPNTrianglesInit_7b, + SP7bitTriangles, +] + class BleedGraphics: # bleed_state "enums" @@ -437,7 +447,8 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in DPLoadBlock, DPLoadTile, DPLoadTLUTCmd, - DPFullSync, *TRI_CMDS + DPFullSync, + *TRI_CMDS, ]: return False From 1adbc7251c2b766ec28db4d90f960e6e2f96ad8a Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 7 Jun 2024 18:52:36 +0100 Subject: [PATCH 15/82] fix ucode check, bleed --- fast64_internal/f3d/f3d_bleed.py | 8 +++++++- fast64_internal/f3d/f3d_gbi.py | 9 ++++++--- fast64_internal/f3d/f3d_material.py | 2 +- fast64_internal/f3d/f3d_writer.py | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 815f1d349..58cec8146 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -50,6 +50,7 @@ GfxList, FTriGroup, GbiMacro, + is_ucode_point_lit, ) TRI_CMDS = [ @@ -102,7 +103,12 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ place_in_flaglist(defaults.g_shade_smooth, "G_SHADING_SMOOTH", setGeo, clearGeo) if bpy.context.scene.f3d_type == "F3DEX_GBI_2" or bpy.context.scene.f3d_type == "F3DEX_GBI": place_in_flaglist(defaults.g_clipping, "G_CLIPPING", setGeo, clearGeo) - + if is_ucode_point_lit(bpy.context.scene.f3d_type): + place_in_flaglist(defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", setGeo, clearGeo) + if bpy.context.scene.f3d_type == "F3DZEX (AC)": + place_in_flaglist(defaults.g_decal_gequal, "G_DECAL_GEQUAL", setGeo, clearGeo) + place_in_flaglist(defaults.g_decal_equal, "G_DECAL_EQUAL", setGeo, clearGeo) + place_in_flaglist(defaults.g_decal_special, "G_DECAL_SPECIAL", setGeo, clearGeo) self.default_load_geo = SPLoadGeometryMode(setGeo.flagList) self.default_set_geo = setGeo self.default_clear_geo = clearGeo diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index c9c1d52a8..9dba1362f 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -132,8 +132,11 @@ def isUcodeF3DEX2(F3D_VER: str) -> bool: def isUcodeF3DEX3(F3D_VER: str) -> bool: return F3D_VER == "F3DEX3" -def isUcodePointLit(F3D_VER: str) -> bool: - return F3D_VER == {"F3DEX3", "F3DZEX (AC)"} + + +def is_ucode_point_lit(F3D_VER: str) -> bool: + return F3D_VER in {"F3DEX3", "F3DZEX (AC)"} + class F3D: """NOTE: do not initialize this class manually! use get_F3D_GBI so that the single instance is cached from the microcode type.""" @@ -146,7 +149,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) F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" - F3D_POINT_LIT = self.F3D_POINT_LIT = F3D_VER == isUcodePointLit(F3D_VER) + F3D_POINT_LIT = self.F3D_POINT_LIT = F3D_VER == is_ucode_point_lit(F3D_VER) # 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 39ef1ee93..6efa2da72 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3114,7 +3114,7 @@ class RDPSettings(PropertyGroup): ) g_lighting_positional: bpy.props.BoolProperty( name="Positional Lighting", - default=False, # TODO: Check with sauren that this should be defaulted to false + default=False, # TODO: Check with sauren that this should be defaulted to false update=update_node_values_with_preset, description="F3DZEX (AC): Enables positional lights", ) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 9e5b76298..c64272bf4 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1642,7 +1642,7 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", *args) if isUcodeF3DEX1(bpy.context.scene.f3d_type): saveFunc(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", *args) - if isUcodePointLit(bpy.context.scene.f3d_type): + if is_ucode_point_lit(bpy.context.scene.f3d_type): saveFunc(settings.g_lighting_positional, defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", *args) From 4afc76642ee1c7719c2432e73342df16d7ff3a7e Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 8 Jun 2024 09:01:22 +0100 Subject: [PATCH 16/82] =?UTF-8?q?Don=C2=B4t=20hide=20positional=20in=20f3d?= =?UTF-8?q?ex3,=20put=20it=20in=20Not=20Useful?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fast64_internal/f3d/f3d_gbi.py | 2 +- fast64_internal/f3d/f3d_material.py | 18 +++++++++++------- fast64_internal/f3d/f3d_parser.py | 11 +++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 9dba1362f..74f1bae8f 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -149,7 +149,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) F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" - F3D_POINT_LIT = self.F3D_POINT_LIT = F3D_VER == is_ucode_point_lit(F3D_VER) + F3D_POINT_LIT = self.F3D_POINT_LIT = is_ucode_point_lit(F3D_VER) # 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 6efa2da72..85e3bb372 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -30,7 +30,7 @@ from mathutils import Color from .f3d_enums import * -from .f3d_gbi import get_F3D_GBI, GBL_c1, GBL_c2, enumTexScroll, isUcodeF3DEX1 +from .f3d_gbi import get_F3D_GBI, GBL_c1, GBL_c2, enumTexScroll, isUcodeF3DEX1, is_ucode_point_lit from .f3d_material_presets import * from ..utility import * from ..render_settings import Fast64RenderSettings_Properties, update_scene_props_from_render_settings @@ -441,7 +441,8 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], return c isF3DEX3 = bpy.context.scene.f3d_type == "F3DEX3" - isF3DZEX_AC = bpy.context.scene.f3d_type == "F3DZEX (AC)" + is_f3dzex_ac = bpy.context.scene.f3d_type == "F3DZEX (AC)" + is_point_lit = is_ucode_point_lit(bpy.context.scene.f3d_type) lightFxPrereq = isF3DEX3 and settings.g_lighting ccWarnings = shadeInCC = False blendWarnings = shadeInBlender = zInBlender = False @@ -460,12 +461,12 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if c is not None: if ccWarnings and not shadeInCC and not settings.g_tex_gen: c.label(text="Shade not used in CC, can disable lighting.", icon="INFO") - if isF3DZEX_AC: - c.prop(settings, "g_lighting_positional") if isF3DEX3: c.prop(settings, "g_packed_normals") c.prop(settings, "g_lighting_specular") c.prop(settings, "g_ambocclusion") + elif is_point_lit: # Draw this flag in Not Useful for f3dex3 + c.prop(settings, "g_lighting_positional") d = indentGroup(c, "g_tex_gen", False) if d is not None: d.prop(settings, "g_tex_gen_linear") @@ -516,7 +517,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], elif blendWarnings and not shadeInBlender and settings.g_fog: c.label(text="Fog not used in rendermode / blender, can disable.", icon="INFO") - if isF3DZEX_AC: + if is_f3dzex_ac: c = indentGroup(inputGroup, "Decals:", True) c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_equal") @@ -554,6 +555,9 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c.prop(settings, "g_lod") if isUcodeF3DEX1(bpy.context.scene.f3d_type): c.prop(settings, "g_clipping") + elif isF3DEX3: + c.prop(settings, "g_lighting_positional") + c.label(text="Always enabled in F3DEX3", icon="INFO") def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): @@ -3114,9 +3118,9 @@ class RDPSettings(PropertyGroup): ) g_lighting_positional: bpy.props.BoolProperty( name="Positional Lighting", - default=False, # TODO: Check with sauren that this should be defaulted to false + default=True, update=update_node_values_with_preset, - description="F3DZEX (AC): Enables positional lights", + description="F3DEX/ZEX: Enables positional lights", ) # upper half mode diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index d61691c4b..bd93f3011 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -902,6 +902,9 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_decal_equal = value if bitFlags & self.f3d.G_DECAL_SPECIAL: rdp_settings.g_decal_special = value + if self.f3d.F3D_POINT_LIT: + if bitFlags & self.f3d.G_LIGHTING_POSITIONAL: + rdp_settings.g_lighting_positional = value if bitFlags & self.f3d.G_FOG: rdp_settings.g_fog = value if bitFlags & self.f3d.G_LIGHTING: @@ -916,8 +919,6 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_shade_smooth = value if bitFlags & self.f3d.G_CLIPPING: rdp_settings.g_clipping = value - if bitFlags & self.f3d.G_LIGHTING_POSITIONAL: - rdp_settings.g_lighting_positional = value def loadGeoFlags(self, command: "ParsedMacro"): mat = self.mat() @@ -956,6 +957,10 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_gequal = False rdp_settings.g_equal = False rdp_settings.g_decal_special = False + if self.f3d.F3D_POINT_LIT: + rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 + else: + rdp_settings.g_lighting_positional = False rdp_settings.g_fog = bitFlags & self.f3d.G_FOG != 0 rdp_settings.g_lighting = bitFlags & self.f3d.G_LIGHTING != 0 @@ -964,8 +969,6 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_lod = bitFlags & self.f3d.G_LOD != 0 rdp_settings.g_shade_smooth = bitFlags & self.f3d.G_SHADING_SMOOTH != 0 rdp_settings.g_clipping = bitFlags & self.f3d.G_CLIPPING != 0 - if self.f3d.F3D_POINT_LIT: - rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 def setCombineLerp(self, lerp0, lerp1): mat = self.mat() From 53a2daf8e6c25e488cc99f9ada3251659c5bbb26 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 8 Jun 2024 09:03:44 +0100 Subject: [PATCH 17/82] Improve description --- 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 85e3bb372..4f1107ba6 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3120,7 +3120,7 @@ class RDPSettings(PropertyGroup): name="Positional Lighting", default=True, update=update_node_values_with_preset, - description="F3DEX/ZEX: Enables positional lights", + description="F3DEX/ZEX: Enables calculating shade color using positional lights along with directional, ignored in F3DEX3", ) # upper half mode From bad3ed1fb53a565d4d2f070ef58409a66c91307b Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 9 Jun 2024 10:56:27 +0100 Subject: [PATCH 18/82] Implement all commands, may need fixes --- fast64_internal/f3d/f3d_gbi.py | 204 +++++++++++++++++++++++++++- fast64_internal/f3d/f3d_material.py | 2 +- 2 files changed, 200 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 74f1bae8f..f60ec7ba5 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -196,9 +196,10 @@ def __init__(self, F3D_VER): if F3DZEX_AC_EXT: self.G_TRIN = 0x09 self.G_TRIN_INDEPEND = 0x0A - - self.G_VTX_MODE_5bit = 0x00 - self.G_VTX_MODE_7bit = 0x01 + self.G_SETTEXEDGEALPHA = 0xCE + self.G_SETCOMBINE_NOTEV = 0xCF + self.G_SETCOMBINE_TEV = 0xD0 + self.G_SETTILE_DOLPHIN = 0xD2 self.G_SPECIAL_1 = 0xD5 self.G_SPECIAL_2 = 0xD4 self.G_SPECIAL_3 = 0xD3 @@ -355,6 +356,19 @@ def __init__(self, F3D_VER): self.G_DECAL_ALWAYS = self.G_DECAL_GEQUAL | self.G_DECAL_LEQUAL self.G_DECAL_SPECIAL = 0x00000040 self.G_DECAL_ALL = self.G_DECAL_ALWAYS | self.G_DECAL_SPECIAL + self.G_TLUT_DOLPHIN = 2 + self.GX_WRAP_MODE_VARS = { + "0": 0, + "GX_CLAMP": 0, + "GX_REPEAT": 1, + "GX_MIRROR": 2, + } + self.G_DOLPHIN_TLUT_DEFAULT_MODE = 15 + self.G_VTX_MODE_5bit = 0x00 + self.G_VTX_MODE_7bit = 0x01 + self.G_SPECIAL_NONE = 0 + self.G_SPECIAL_UNKNOWN = 1 + self.G_SPECIAL_TA_MODE = 2 else: self.G_CLIPPING = 0x00000000 @@ -3783,7 +3797,7 @@ def to_binary(self, f3d, segments): | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), ) else: - raise PluginError("SP5bitTriangles not available in F3DZEX (AC).") + raise PluginError("SP5bitTriangles only available in F3DZEX (AC).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -3841,7 +3855,7 @@ def to_binary(self, f3d, segments): ), ) else: - raise PluginError("SP7bitTriangles not available in F3DZEX (AC).") + raise PluginError("SP7bitTriangles only available in F3DZEX (AC).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -4784,6 +4798,36 @@ def to_binary(self, f3d, segments): return gsSetImage(f3d.G_SETTIMG, fmt, siz, self.width, imagePtr) +@dataclass(unsafe_hash=True) +class DPSetTextureImage_Dolphin(GbiMacro): + fmt: str + siz: str + height: int + width: int + image: FImage + # TODO: Should this use segmented to virtual? + # _segptrs = True # calls segmented_to_virtual on name when needed + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + fmt = f3d.G_IM_FMT_VARS[self.fmt] + siz = f3d.G_IM_SIZ_VARS[self.siz] + image_ptr = int.from_bytes(encodeSegmentedAddr(self.image.startAddress, segments), "big") + words = ( + _SHIFTL(f3d.G_SETTIMG, 24, 8) + | _SHIFTL(self.fmt, 21, 3) + | _SHIFTL(self.siz, 19, 2) + | _SHIFTL(1, 18, 1) + | _SHIFTL((self.height / 4) - 1, 10, 8) + | _SHIFTL((self.width - 1), 0, 10), + image_ptr, + ) + else: + raise PluginError("DPSetTextureImage_Dolphin only available in F3DZEX (AC).") + + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def gsDPSetCombine(muxs0, muxs1, f3d): words = _SHIFTL(f3d.G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), muxs1 return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -4970,6 +5014,18 @@ def to_binary(self, f3d, segments): return SPLightToRDP(self.light, self.alpha, word0).to_binary(f3d, segments) +@dataclass(unsafe_hash=True) +class DPSetTexEdgeAlpha(GbiMacro): + alpha: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = (_SHIFTL(f3d.G_SETTEXEDGEALPHA, 24, 8), _SHIFTL(self.alpha, 0, 8)) + else: + raise PluginError("DPSetTexEdgeAlpha only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + @dataclass(unsafe_hash=True) class DPSetOtherMode(GbiMacro): mode0: list @@ -5002,6 +5058,45 @@ def is_LOADTILE(self, f3d): return self.t == f3d.G_TX_LOADTILE +@dataclass(unsafe_hash=True) +class DPSetTileSize_Dolphin(GbiMacro): + tile: int + s: int + t: int + width: int + height: int + + def to_binary(self, f3d, segments): + # TODO: This is how emu64 converts n64 to dolphin + # u32 s_len = (settilesize->sh - settilesize->sl) / 4; + # u32 t_len = (settilesize->th - settilesize->tl) / 4; + if f3d.F3DZEX_AC_EXT: + words = ( + (_SHIFTL(G_SETTILESIZE, 24, 8) | _SHIFTL(self.s, 10, 14) | _SHIFTL(self.width - 1, 0, 10)), + ( + _SHIFTL(1, 31, 1) + | _SHIFTL(self.tile, 24, 3) + | _SHIFTL(self.t, 10, 14) + | _SHIFTL(self.height - 1, 0, 10) + ), + ) + else: + raise PluginError("DPSetTileSize_Dolphin only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +@dataclass(unsafe_hash=True) +class DPSetTextureAdjustMode(GbiMacro): + mode: str + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = (_SHIFTL(f3d.G_SPECIAL_1, 24, 8) | _SHIFTL(G_SPECIAL_TA_MODE, 16, 8) | _SHIFTL(mode, 0, 16), 0) + else: + raise PluginError("DPSetTextureAdjustMode only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + @dataclass(unsafe_hash=True) class DPLoadTile(GbiMacro): tile: int @@ -5055,6 +5150,36 @@ def is_LOADTILE(self, f3d): return self.tile == f3d.G_TX_LOADTILE +@dataclass(unsafe_hash=True) +class DPSetTile_Dolphin(GbiMacro): + fmt: str + tile: int + tlut_name: int + wrap_s: int + wrap_t: int + shift_s: int + shift_t: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + ( + _SHIFTL(f3d.G_SETTILE_DOLPHIN, 24, 8) + | _SHIFTL(f3d.G_IM_FMT_VARS[self.fmt], 20, 4) + | _SHIFTL(self.tile, 16, 3) + | _SHIFTL(self.tlut_name, 12, 4) + | _SHIFTL(f3d.GX_WRAP_MODE_VARS[self.wrap_s], 10, 2) + | _SHIFTL(f3d.GX_WRAP_MODE_VARS[self.wrap_t], 8, 2) + | _SHIFTL(self.shift_s, 4, 4) + | _SHIFTL(self.shift_t, 0, 4) + ), + 0, + ) + else: + raise PluginError("DPSetTile_Dolphin only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + @dataclass(unsafe_hash=True) class DPLoadBlock(GbiMacro): tile: int @@ -5377,6 +5502,34 @@ def size(self, f3d): return GFX_SIZE * 7 +@dataclass(unsafe_hash=True) +class DPLoadTextureBlock_4b_Dolphin(GbiMacro): + timg: FImage + fmt: str + width: int + height: int + pal: int + ws: int + wt: int + ss: int + st: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( + f3d, segments + ) + DPSetTile_Dolphin( + f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, 0, self.pal, self.ws, self.wt, self.ss, self.st + ).to_binary( + f3d, segments + ) + else: + raise PluginError("gsDPLoadTextureBlock_4b_Dolphin only available in F3DZEX (AC).") + + def size(self, f3d): + return GFX_SIZE * 2 + + # gsDPLoadTextureBlock_4bS # gsDPLoadMultiBlock_4b # gsDPLoadMultiBlock_4bS @@ -5532,6 +5685,25 @@ def size(self, f3d): return GFX_SIZE * 7 +@dataclass(unsafe_hash=True) +class DPLoadTextureTile_4b_Dolphin(GbiMacro): + timg: FImage + fmt: str + width: int + height: int + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( + f3d, segments + ) + DPSetTile_Dolphin(f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + else: + raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") + + def size(self, f3d): + return GFX_SIZE * 2 + + # gsDPLoadMultiTile_4b @@ -5597,6 +5769,28 @@ def size(self, f3d): return GFX_SIZE * 6 +@dataclass(unsafe_hash=True) +class DPLoadTLUT_Dolphin(GbiMacro): + name: int + count: int + unk: int # Always 1? + addr: FImage + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + _SHIFTL(f3d.G_LOADTLUT, 24, 8) + | _SHIFTL(f3d.G_TLUT_DOLPHIN, 22, 2) + | _SHIFTL(self.name, 16, 4) + | _SHIFTL(self.unk, 14, 2) + | _SHIFTL(self.count, 0, 14), + self.addr, + ) + else: + raise PluginError("DPLoadTLUT_Dolphin only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + # gsDPSetScissor # gsDPSetScissorFrac diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 4f1107ba6..7c7141543 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -465,7 +465,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c.prop(settings, "g_packed_normals") c.prop(settings, "g_lighting_specular") c.prop(settings, "g_ambocclusion") - elif is_point_lit: # Draw this flag in Not Useful for f3dex3 + elif is_point_lit: # Draw this flag in Not Useful for f3dex3 c.prop(settings, "g_lighting_positional") d = indentGroup(c, "g_tex_gen", False) if d is not None: From ce8b6df46556196de126981e32426ad3a458d31e Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 9 Jun 2024 10:59:06 +0100 Subject: [PATCH 19/82] Finish this --- fast64_internal/f3d/f3d_gbi.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index f60ec7ba5..51df3fa24 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -369,6 +369,11 @@ def __init__(self, F3D_VER): self.G_SPECIAL_NONE = 0 self.G_SPECIAL_UNKNOWN = 1 self.G_SPECIAL_TA_MODE = 2 + self.TA_ADJUST_MODE_VARS = { + "0": 0, + "G_TA_N64": 0, + "G_TA_DOLPHIN": 1, + } else: self.G_CLIPPING = 0x00000000 @@ -5091,7 +5096,12 @@ class DPSetTextureAdjustMode(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: - words = (_SHIFTL(f3d.G_SPECIAL_1, 24, 8) | _SHIFTL(G_SPECIAL_TA_MODE, 16, 8) | _SHIFTL(mode, 0, 16), 0) + words = ( + _SHIFTL(f3d.G_SPECIAL_1, 24, 8) + | _SHIFTL(f3d.G_SPECIAL_TA_MODE, 16, 8) + | _SHIFTL(f3d.TA_ADJUST_MODE_VARS[mode], 0, 16), + 0, + ) else: raise PluginError("DPSetTextureAdjustMode only available in F3DZEX (AC).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") From 890d61e99c0687ec04ac0689f2fe9e0b8a87dba1 Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 10 Jun 2024 10:17:17 +0100 Subject: [PATCH 20/82] implement in bleed --- fast64_internal/f3d/f3d_bleed.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 58cec8146..b4646ab71 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -32,15 +32,18 @@ SPSetOtherMode, DPLoadBlock, DPLoadTLUTCmd, + DPLoadTLUT_Dolphin, DPFullSync, DPSetRenderMode, DPSetTextureLUT, DPSetCycleType, DPSetTextureImage, + DPSetTextureImage_Dolphin, DPPipeSync, DPLoadSync, DPTileSync, DPSetTile, + DPSetTile_Dolphin, DPLoadTile, FModel, FMesh, @@ -206,12 +209,12 @@ def build_tmem_dict(self, cmd_list: GfxList): tmem_dict = dict() tile_dict = {i: 0 for i in range(8)} # an assumption that hopefully never needs correction for cmd in cmd_list.commands: - if type(cmd) == DPSetTextureImage: + if type(cmd) in (DPSetTextureImage, DPSetTextureImage_Dolphin): im_buffer = cmd continue - if type(cmd) == DPSetTile: + if type(cmd) in (DPSetTile, DPSetTile_Dolphin): tile_dict[cmd.tile] = cmd.tmem - if type(cmd) in (DPLoadTLUTCmd, DPLoadTile, DPLoadBlock): + if type(cmd) in (DPLoadTLUTCmd, DPLoadTLUT_Dolphin, DPLoadTile, DPLoadBlock): tmem_dict[tile_dict[cmd.tile]] = im_buffer continue return tmem_dict @@ -238,9 +241,9 @@ def bleed_textures(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: commands_bled.commands[j] = None rm_load = True continue - if rm_load and type(cmd) == DPSetTile: + if rm_load and type(cmd) in (DPSetTile, DPSetTile_Dolphin): commands_bled.commands[j] = None - if rm_load and type(cmd) in (DPLoadTLUTCmd, DPLoadTile, DPLoadBlock): + if rm_load and type(cmd) in (DPLoadTLUTCmd, DPLoadTLUT_Dolphin, DPLoadTile, DPLoadBlock): commands_bled.commands[j] = None rm_load = None continue @@ -450,9 +453,11 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in SPModifyVertex, SPEndDisplayList, DPSetTextureImage, + DPSetTextureImage_Dolphin, DPLoadBlock, DPLoadTile, DPLoadTLUTCmd, + DPLoadTLUT_Dolphin, DPFullSync, *TRI_CMDS, ]: From 34a46e78a9c7026d001e8215def6fc6163d01bda Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 10 Jun 2024 11:57:45 +0100 Subject: [PATCH 21/82] Texedge alpha ui, write and parse --- fast64_internal/f3d/f3d_material.py | 30 +++++++++++++++++++++++++++++ fast64_internal/f3d/f3d_parser.py | 4 ++++ fast64_internal/f3d/f3d_writer.py | 3 +++ 3 files changed, 37 insertions(+) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 7c7141543..8374a0866 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -628,6 +628,21 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input_name.prop(dataHolder, "set_blend", text="Blend Color") prop_input.prop(dataHolder, "blend_color", text="") prop_input.enabled = dataHolder.set_blend + if bpy.context.scene.f3d_type == "F3DZEX (AC)": + tex_edge_alpha_group = layout.column() + is_tex_edge_mode = ( + (settings.aa_en and settings.cvg_x_alpha and settings.alpha_cvg_sel) + and settings.cvg_dst == "CVG_DST_CLAMP" + and settings.zmode == "ZMODE_OPA" + ) + tex_edge_alpha_row = tex_edge_alpha_group.row() + prop_input_name = tex_edge_alpha_row.column() + prop_input = tex_edge_alpha_row.column() + prop_input_name.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") + prop_input.prop(dataHolder, "tex_edge_alpha", text="") + prop_input.enabled = dataHolder.set_tex_edge_alpha + if not is_tex_edge_mode: + tex_edge_alpha_group.label(text="Material is not recognised as Tex Edge", icon="INFO") def tmemUsageUI(layout, textureProp): @@ -3965,6 +3980,10 @@ class F3DMaterialProperty(PropertyGroup): default=False, update=update_node_values_with_preset, ) + set_tex_edge_alpha: bpy.props.BoolProperty( + default=False, + update=update_node_values_with_preset, + ) set_key: bpy.props.BoolProperty( default=True, update=update_node_values_with_preset, @@ -3991,6 +4010,15 @@ class F3DMaterialProperty(PropertyGroup): max=1, default=(0, 0, 0, 1), ) + tex_edge_alpha: bpy.props.FloatProperty( + name="Tex Edge Alpha", + min=0, + max=1, + step=100.0/255.0, + default=144.0/255.0, + update=update_node_values_with_preset, # TODO: This shouldnt need to actually interact with the nodes, maybe implement? + description="F3DZEX (AC): Used in the second comparison for GXSetAlphaCompare with GX_GEQUAL when the using a tex edge material", + ) prim_color: bpy.props.FloatVectorProperty( name="Primitive Color", subtype="COLOR", @@ -4263,6 +4291,7 @@ def key(self) -> F3DMaterialHash: else None, self.use_default_lighting, self.set_blend, + self.set_tex_edge_alpha, self.set_prim, self.set_env, self.set_key, @@ -4271,6 +4300,7 @@ def key(self) -> F3DMaterialHash: self.set_lights, self.set_fog, tuple([round(value, 4) for value in self.blend_color]) if self.set_blend else None, + round(self.tex_edge_alpha, 4) if self.set_tex_edge_alpha else None, tuple([round(value, 4) for value in self.prim_color]) if self.set_prim else None, round(self.prim_lod_frac, 4) if self.set_prim else None, round(self.prim_lod_min, 4) if self.set_prim else None, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index bd93f3011..a5fef8178 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -556,6 +556,7 @@ def clearMaterial(self): mat.set_lights = False mat.set_env = False mat.set_blend = False + mat.set_tex_edge_alpha = False mat.set_key = False mat.set_k0_5 = False @@ -1717,6 +1718,9 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr elif command.name == "gsDPSetBlendColor": mat.blend_color = self.gammaInverseParam(command.params) mat.set_blend = True + elif command.name == "gsDPSetTexEdgeAlpha": # F3DEX (AC) + mat.tex_edge_alpha = math_eval(command.params[0], self.f3d) / 255 + mat.set_tex_edge_alpha = True elif command.name == "gsDPSetFogColor": mat.fog_color = self.gammaInverseParam(command.params) mat.set_fog = True diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index c64272bf4..86a8dd649 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1856,6 +1856,9 @@ def saveOtherDefinition(fMaterial, material, defaults): int(material.blend_color[3] * 255), ) ) + if bpy.context.scene.f3d_type == "F3DZEX (AC)": + if material.set_tex_edge_alpha: + fMaterial.mat_only_DL.commands.append(DPSetTexEdgeAlpha(int(material.tex_edge_alpha * 255))) enumMatWriteMethod = [ From 0bd58bc2a5311436124601ec124b98dbeb1e76a1 Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 10 Jun 2024 12:27:12 +0100 Subject: [PATCH 22/82] fix description --- 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 8374a0866..ebf1b41cf 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -4017,7 +4017,7 @@ class F3DMaterialProperty(PropertyGroup): step=100.0/255.0, default=144.0/255.0, update=update_node_values_with_preset, # TODO: This shouldnt need to actually interact with the nodes, maybe implement? - description="F3DZEX (AC): Used in the second comparison for GXSetAlphaCompare with GX_GEQUAL when the using a tex edge material", + description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal.", ) prim_color: bpy.props.FloatVectorProperty( name="Primitive Color", From 692d30cc426b533783fc273ef86cab1d9e536b0d Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 10 Jun 2024 12:39:43 +0100 Subject: [PATCH 23/82] Implement alpha threshold in viewport --- fast64_internal/f3d/f3d_material.py | 28 ++++++++++++++++++---------- fast64_internal/f3d/f3d_parser.py | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index ebf1b41cf..c553f160b 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -303,7 +303,10 @@ def get_blend_method(material: bpy.types.Material) -> str: def update_blend_method(material: Material, context): material.blend_method = get_blend_method(material) if material.blend_method == "CLIP": - material.alpha_threshold = 0.125 + if context.scene.f3d_type == "F3DZEX (AC)" and material.f3d_mat.rdp_settings.is_emu64_texedge: + material.alpha_threshold = material.f3d_mat.tex_edge_alpha + else: + material.alpha_threshold = 0.125 class DrawLayerProperty(PropertyGroup): @@ -630,18 +633,13 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input.enabled = dataHolder.set_blend if bpy.context.scene.f3d_type == "F3DZEX (AC)": tex_edge_alpha_group = layout.column() - is_tex_edge_mode = ( - (settings.aa_en and settings.cvg_x_alpha and settings.alpha_cvg_sel) - and settings.cvg_dst == "CVG_DST_CLAMP" - and settings.zmode == "ZMODE_OPA" - ) tex_edge_alpha_row = tex_edge_alpha_group.row() prop_input_name = tex_edge_alpha_row.column() prop_input = tex_edge_alpha_row.column() prop_input_name.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") prop_input.prop(dataHolder, "tex_edge_alpha", text="") prop_input.enabled = dataHolder.set_tex_edge_alpha - if not is_tex_edge_mode: + if not settings.is_emu64_texedge: tex_edge_alpha_group.label(text="Material is not recognised as Tex Edge", icon="INFO") @@ -3368,6 +3366,16 @@ class RDPSettings(PropertyGroup): update=update_node_values_with_preset, ) + @property + def is_emu64_texedge(self): + return ( + self.aa_en + and self.cvg_x_alpha + and self.alpha_cvg_sel + and self.cvg_dst == "CVG_DST_CLAMP" + and self.zmode == "ZMODE_OPA" + ) + def key(self): setRM = self.set_rendermode rmAdv = self.rendermode_advanced_enabled @@ -4014,9 +4022,9 @@ class F3DMaterialProperty(PropertyGroup): name="Tex Edge Alpha", min=0, max=1, - step=100.0/255.0, - default=144.0/255.0, - update=update_node_values_with_preset, # TODO: This shouldnt need to actually interact with the nodes, maybe implement? + step=100.0 / 255.0, + default=144.0 / 255.0, + update=update_node_values_with_preset, # TODO: This shouldnt need to actually interact with the nodes, maybe implement? description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal.", ) prim_color: bpy.props.FloatVectorProperty( diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index a5fef8178..bf17a1630 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -1718,7 +1718,7 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr elif command.name == "gsDPSetBlendColor": mat.blend_color = self.gammaInverseParam(command.params) mat.set_blend = True - elif command.name == "gsDPSetTexEdgeAlpha": # F3DEX (AC) + elif command.name == "gsDPSetTexEdgeAlpha": # F3DEX (AC) mat.tex_edge_alpha = math_eval(command.params[0], self.f3d) / 255 mat.set_tex_edge_alpha = True elif command.name == "gsDPSetFogColor": From 790f6d9907c5f85af527e855f800375e0c4791ae Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 10 Jun 2024 16:17:15 +0100 Subject: [PATCH 24/82] First implementation of set tile and set image --- fast64_internal/f3d/f3d_bleed.py | 2 +- fast64_internal/f3d/f3d_texture_writer.py | 37 +++++++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index b4646ab71..41807ca32 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -212,7 +212,7 @@ def build_tmem_dict(self, cmd_list: GfxList): if type(cmd) in (DPSetTextureImage, DPSetTextureImage_Dolphin): im_buffer = cmd continue - if type(cmd) in (DPSetTile, DPSetTile_Dolphin): + if type(cmd) == DPSetTile: tile_dict[cmd.tile] = cmd.tmem if type(cmd) in (DPLoadTLUTCmd, DPLoadTLUT_Dolphin, DPLoadTile, DPLoadBlock): tmem_dict[tile_dict[cmd.tile]] = im_buffer diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 6a8ee8af9..434ab9e64 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -206,7 +206,10 @@ def maybeSaveSingleLargeTextureSetup( sm = 2 if is4bit else 4 nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if curImgSet != i: - gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) + if f3d.F3DZEX_AC_EXT: + gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, texDimensions[1], wid, fImage)) + else: + gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) def loadOneOrTwoS(tmemBase, tidxBase, TL, TH): if line != curTileLines[tidxBase]: @@ -953,9 +956,11 @@ def saveTextureLoadOnly( # LoadTile will pad rows to 64 bit word alignment, while # LoadBlock assumes this is already done. - useLoadBlock = canUseLoadBlock(fImage, texProp.tex_format, f3d) + is_f3dzex_ac_ext = not f3d.F3DZEX_AC_EXT + useLoadBlock = canUseLoadBlock(fImage, texProp.tex_format, f3d) and is_f3dzex_ac_ext line = 0 if useLoadBlock else getTileLine(fImage, SL, SH, siz, f3d) wid = 1 if useLoadBlock else fImage.width + height = 1 if useLoadBlock else fImage.height if siz == "G_IM_SIZ_4b": if useLoadBlock: @@ -963,7 +968,7 @@ def saveTextureLoadOnly( dxt = f3d.CALC_DXT_4b(fImage.width) siz = "G_IM_SIZ_16b" loadCommand = DPLoadBlock(loadtile, 0, 0, dxs, dxt) - else: + elif is_f3dzex_ac_ext: sl2 = int(SL * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) sh2 = int(SH * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) siz = "G_IM_SIZ_8b" @@ -978,14 +983,18 @@ def saveTextureLoadOnly( dxt = f3d.CALC_DXT(fImage.width, f3d.G_IM_SIZ_VARS[siz + "_BYTES"]) siz += "_LOAD_BLOCK" loadCommand = DPLoadBlock(loadtile, 0, 0, dxs, dxt) - else: + elif is_f3dzex_ac_ext: loadCommand = DPLoadTile(loadtile, sl, tl, sh, th) if not omitSetTextureImage: - gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) - if not omitSetTile: - gfxOut.commands.append(DPSetTile(fmt, siz, line, tmem, loadtile, 0, nocm, 0, 0, nocm, 0, 0)) - gfxOut.commands.append(loadCommand) + if f3d.F3DZEX_AC_EXT: + gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, height, wid, fImage)) + else: + gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) + if is_f3dzex_ac_ext: + if not omitSetTile: + gfxOut.commands.append(DPSetTile(fmt, siz, line, tmem, loadtile, 0, nocm, 0, 0, nocm, 0, 0)) + gfxOut.commands.append(loadCommand) def saveTextureTile( @@ -1029,8 +1038,16 @@ def saveTextureTile( SL, _, SH, _, sl, tl, sh, th = getTileSizeSettings(texProp, tileSettings, f3d) line = getTileLine(fImage, SL, SH, siz, f3d) - tileCommand = DPSetTile(fmt, siz, line, tmem, rendertile, pal, cmt, maskt, shiftt, cms, masks, shifts) - tileSizeCommand = DPSetTileSize(rendertile, sl, tl, sh, th) + if f3d.F3DZEX_AC_EXT: + if (clamp_S and mirror_S) or (clamp_T and mirror_T): + raise PluginError("Clamp + mirror not supported in F3DZEX (AC)\n") + wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" + wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" + tileCommand = DPSetTile_Dolphin(fmt, rendertile, f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, wrap_s, wrap_t, shifts, shiftt) + tileSizeCommand = DPSetTileSize(rendertile, sl, tl, fImage.width, fImage.height) + else: + 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}") if scrollInfo.s or scrollInfo.t: From 008ca6689c0767e334cd84df19118500f1d3f897 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 11 Jun 2024 10:35:30 +0100 Subject: [PATCH 25/82] First pallete implementation, fixed bleed --- fast64_internal/f3d/f3d_bleed.py | 9 +++++--- fast64_internal/f3d/f3d_gbi.py | 10 ++++----- fast64_internal/f3d/f3d_texture_writer.py | 25 ++++++++++++++++++----- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 41807ca32..471a1f48c 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -212,11 +212,14 @@ def build_tmem_dict(self, cmd_list: GfxList): if type(cmd) in (DPSetTextureImage, DPSetTextureImage_Dolphin): im_buffer = cmd continue + elif type(cmd) == DPSetTile_Dolphin: + tmem_dict[cmd.name + 15] = im_buffer + elif type(cmd) == DPLoadTLUT_Dolphin: + tmem_dict[cmd.tlut_name] = cmd # loadtlut_dolphin loads on its own if type(cmd) == DPSetTile: tile_dict[cmd.tile] = cmd.tmem - if type(cmd) in (DPLoadTLUTCmd, DPLoadTLUT_Dolphin, DPLoadTile, DPLoadBlock): + if type(cmd) in (DPLoadTLUTCmd, DPLoadTile, DPLoadBlock): tmem_dict[tile_dict[cmd.tile]] = im_buffer - continue return tmem_dict def bleed_textures(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): @@ -241,7 +244,7 @@ def bleed_textures(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: commands_bled.commands[j] = None rm_load = True continue - if rm_load and type(cmd) in (DPSetTile, DPSetTile_Dolphin): + if rm_load and type(cmd) == DPSetTile: commands_bled.commands[j] = None if rm_load and type(cmd) in (DPLoadTLUTCmd, DPLoadTLUT_Dolphin, DPLoadTile, DPLoadBlock): commands_bled.commands[j] = None diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 51df3fa24..099505e00 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -5164,7 +5164,7 @@ def is_LOADTILE(self, f3d): class DPSetTile_Dolphin(GbiMacro): fmt: str tile: int - tlut_name: int + name: int wrap_s: int wrap_t: int shift_s: int @@ -5177,7 +5177,7 @@ def to_binary(self, f3d, segments): _SHIFTL(f3d.G_SETTILE_DOLPHIN, 24, 8) | _SHIFTL(f3d.G_IM_FMT_VARS[self.fmt], 20, 4) | _SHIFTL(self.tile, 16, 3) - | _SHIFTL(self.tlut_name, 12, 4) + | _SHIFTL(self.name, 12, 4) | _SHIFTL(f3d.GX_WRAP_MODE_VARS[self.wrap_s], 10, 2) | _SHIFTL(f3d.GX_WRAP_MODE_VARS[self.wrap_t], 8, 2) | _SHIFTL(self.shift_s, 4, 4) @@ -5534,7 +5534,7 @@ def to_binary(self, f3d, segments): f3d, segments ) else: - raise PluginError("gsDPLoadTextureBlock_4b_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPLoadTextureBlock_4b_Dolphin only available in F3DZEX (AC).") def size(self, f3d): return GFX_SIZE * 2 @@ -5781,7 +5781,7 @@ def size(self, f3d): @dataclass(unsafe_hash=True) class DPLoadTLUT_Dolphin(GbiMacro): - name: int + tlut_name: int count: int unk: int # Always 1? addr: FImage @@ -5791,7 +5791,7 @@ def to_binary(self, f3d, segments): words = ( _SHIFTL(f3d.G_LOADTLUT, 24, 8) | _SHIFTL(f3d.G_TLUT_DOLPHIN, 22, 2) - | _SHIFTL(self.name, 16, 4) + | _SHIFTL(self.tlut_name, 16, 4) | _SHIFTL(self.unk, 14, 2) | _SHIFTL(self.count, 0, 14), self.addr, diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 434ab9e64..e0f371e84 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -533,7 +533,7 @@ def writeAll( loadGfx = fMaterial.texture_DL f3d = fModel.f3d if self.loadPal: - savePaletteLoad(loadGfx, fPalette, self.palFormat, self.palAddr, self.palLen, 5 - self.indexInMat, f3d) + savePaletteLoad(loadGfx, fPalette, self.palIndex, self.palFormat, self.palAddr, self.palLen, 5 - self.indexInMat, f3d) if self.doTexLoad: saveTextureLoadOnly(fImage, loadGfx, self.texProp, None, 7 - self.indexInMat, self.texAddr, f3d) if self.doTexTile: @@ -625,7 +625,16 @@ def writeAll( # Determine how to arrange / load palette entries into upper half of tmem if self.isCI: assert self.ti0.useTex or self.ti1.useTex - if not self.ti1.useTex: + if fModel.f3d.F3DZEX_AC_EXT: # TODO: This is kinda hacky, and the AC has palletes reserved for enviromental stuff apperantly? + if self.ti0.useTex: + self.ti0.palIndex = 15 + self.ti0.palLen = len(self.ti0.pal) + self.ti0.loadPal = True + if self.ti1.useTex: + self.ti1.palIndex = 14 + self.ti1.palLen = len(self.ti1.pal) + self.ti1.loadPal = True + elif not self.ti1.useTex: self.ti0.loadPal = True elif not self.ti0.useTex: self.ti1.loadPal = True @@ -763,7 +772,7 @@ def writeAll( fMaterial.texPaletteIndex = [self.ti0.palIndex, self.ti1.palIndex] self.ti0.palBaseName = self.ti0.getPaletteName() self.ti1.palBaseName = self.ti1.getPaletteName() - if self.isCI and self.ti0.useTex and self.ti1.useTex and not self.ti1.loadPal: + if not fModel.f3d.F3DZEX_AC_EXT and self.isCI and self.ti0.useTex and self.ti1.useTex and not self.ti1.loadPal: self.ti0.palBaseName = self.ti0.palBaseName + "_x_" + self.ti1.palBaseName self.ti1.pal = self.ti0.pal @@ -1043,8 +1052,8 @@ def saveTextureTile( raise PluginError("Clamp + mirror not supported in F3DZEX (AC)\n") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" - tileCommand = DPSetTile_Dolphin(fmt, rendertile, f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, wrap_s, wrap_t, shifts, shiftt) - tileSizeCommand = DPSetTileSize(rendertile, sl, tl, fImage.width, fImage.height) + tileCommand = DPSetTile_Dolphin(fmt, rendertile, pal, wrap_s, wrap_t, shifts, shiftt) + tileSizeCommand = DPSetTileSize_Dolphin(rendertile, sl, tl, fImage.width, fImage.height) else: tileCommand = DPSetTile(fmt, siz, line, tmem, rendertile, pal, cmt, maskt, shiftt, cms, masks, shifts) tileSizeCommand = DPSetTileSize(rendertile, sl, tl, sh, th) @@ -1068,6 +1077,7 @@ def saveTextureTile( def savePaletteLoad( gfxOut: GfxList, fPalette: FImage, + palIndex: int, palFormat: str, palAddr: int, palLen: int, @@ -1077,6 +1087,11 @@ def savePaletteLoad( assert 0 <= palAddr < 256 and (palAddr & 0xF) == 0 palFmt = texFormatOf[palFormat] nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] + if f3d.F3DZEX_AC_EXT: + gfxOut.commands.append( + DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette) + ) + return gfxOut.commands.extend( [ DPSetTextureImage(palFmt, "G_IM_SIZ_16b", 1, fPalette), From fe1ae63d822355a159aaed6908428c1f8e820a50 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 11 Jun 2024 11:32:18 +0100 Subject: [PATCH 26/82] Implement "Supports Point Lighting" toggle for f3dex2 family of ucodes Also used the cached f3d definition class for consistency, parts of the ui already did this, only meaningful change was bleed --- __init__.py | 8 ++++++ fast64_internal/f3d/f3d_bleed.py | 19 +++++++------- fast64_internal/f3d/f3d_gbi.py | 30 ++++++++++++++--------- fast64_internal/f3d/f3d_material.py | 21 ++++++++-------- fast64_internal/f3d/f3d_parser.py | 4 +-- fast64_internal/f3d/f3d_texture_writer.py | 12 +++++---- fast64_internal/f3d/f3d_writer.py | 9 ++++--- 7 files changed, 59 insertions(+), 44 deletions(-) diff --git a/__init__.py b/__init__.py index a1be01a17..a5e500b9c 100644 --- a/__init__.py +++ b/__init__.py @@ -12,6 +12,7 @@ from .fast64_internal.oot.props_panel_main import OOT_ObjectProperties from .fast64_internal.utility_anim import utility_anim_register, utility_anim_unregister, ArmatureApplyWithMeshOperator +from .fast64_internal.f3d.f3d_gbi import isUcodeF3DEX2, ucode_can_point_lit, ucode_always_point_lit from .fast64_internal.f3d.f3d_material import mat_register, mat_unregister from .fast64_internal.f3d.f3d_render_engine import render_engine_register, render_engine_unregister from .fast64_internal.f3d.f3d_writer import f3d_writer_register, f3d_writer_unregister @@ -66,7 +67,10 @@ def poll(cls, context): def draw(self, context): col = self.layout.column() col.scale_y = 1.1 # extra padding + fast64_settings = context.scene.fast64.settings prop_split(col, context.scene, "f3d_type", "F3D Microcode") + if ucode_can_point_lit(context.scene.f3d_type) and not ucode_always_point_lit(context.scene.f3d_type): + col.prop(fast64_settings, "point_lit") col.prop(context.scene, "saveTextures") col.prop(context.scene, "f3d_simple", text="Simple Material UI") col.prop(context.scene, "generateF3DNodeGraph", text="Generate F3D Node Graph For Materials") @@ -175,6 +179,10 @@ class Fast64Settings_Properties(bpy.types.PropertyGroup): name="Prefer RGBA Over CI", description="When enabled, fast64 will default colored textures's format to RGBA even if they fit CI requirements, with the exception of textures that would not fit into TMEM otherwise", ) + point_lit: bpy.props.BoolProperty( + name="Supports Point Ligthing", + description="When enabled, fast64 will export expecting a gbi that supports point lighting, such as Majora's Mask's ucode", + ) class Fast64_Properties(bpy.types.PropertyGroup): diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 471a1f48c..70c7971ce 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -53,7 +53,7 @@ GfxList, FTriGroup, GbiMacro, - is_ucode_point_lit, + get_F3D_GBI, ) TRI_CMDS = [ @@ -78,8 +78,7 @@ class BleedGraphics: def __init__(self): self.bled_gfx_lists = dict() # build world default cmds to compare against, f3d types needed for reset cmd building - self.is_f3d_old = bpy.context.scene.f3d_type == "F3D" - self.is_f3dex2 = "F3DEX2" in bpy.context.scene.f3d_type + self.f3d = get_F3D_GBI() self.build_default_geo() self.build_default_othermodes() @@ -104,11 +103,11 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ place_in_flaglist(defaults.g_tex_gen, "G_TEXTURE_GEN", setGeo, clearGeo) place_in_flaglist(defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", setGeo, clearGeo) place_in_flaglist(defaults.g_shade_smooth, "G_SHADING_SMOOTH", setGeo, clearGeo) - if bpy.context.scene.f3d_type == "F3DEX_GBI_2" or bpy.context.scene.f3d_type == "F3DEX_GBI": + if self.f3d.F3D_OLD_GBI: place_in_flaglist(defaults.g_clipping, "G_CLIPPING", setGeo, clearGeo) - if is_ucode_point_lit(bpy.context.scene.f3d_type): + if self.f3d.POINT_LIT_GBI: place_in_flaglist(defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", setGeo, clearGeo) - if bpy.context.scene.f3d_type == "F3DZEX (AC)": + if self.f3d.F3DZEX_AC_EXT: place_in_flaglist(defaults.g_decal_gequal, "G_DECAL_GEQUAL", setGeo, clearGeo) place_in_flaglist(defaults.g_decal_equal, "G_DECAL_EQUAL", setGeo, clearGeo) place_in_flaglist(defaults.g_decal_special, "G_DECAL_SPECIAL", setGeo, clearGeo) @@ -119,9 +118,9 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ def build_default_othermodes(self): defaults = bpy.context.scene.world.rdp_defaults - othermode_H = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - self.is_f3d_old, []) + othermode_H = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20 - self.f3d.F3D_OLD_GBI, []) # if the render mode is set, it will be consider non-default a priori - othermode_L = SPSetOtherMode("G_SETOTHERMODE_L", 0, 3 - self.is_f3d_old, []) + othermode_L = SPSetOtherMode("G_SETOTHERMODE_L", 0, 3 - self.f3d.F3D_OLD_GBI, []) othermode_L.flagList.append(defaults.g_mdsft_alpha_compare) othermode_L.flagList.append(defaults.g_mdsft_zsrcsel) @@ -215,7 +214,7 @@ def build_tmem_dict(self, cmd_list: GfxList): elif type(cmd) == DPSetTile_Dolphin: tmem_dict[cmd.name + 15] = im_buffer elif type(cmd) == DPLoadTLUT_Dolphin: - tmem_dict[cmd.tlut_name] = cmd # loadtlut_dolphin loads on its own + tmem_dict[cmd.tlut_name] = cmd # loadtlut_dolphin loads on its own if type(cmd) == DPSetTile: tile_dict[cmd.tile] = cmd.tmem if type(cmd) in (DPLoadTLUTCmd, DPLoadTile, DPLoadBlock): @@ -432,7 +431,7 @@ def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: SPSetOtherMode( "G_SETOTHERMODE_L", 0, - 32 - self.is_f3d_old, + 32 - self.f3d.F3D_OLD_GBI, [*self.default_othermode_L.flagList, *default_render_mode], ) ) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 099505e00..882dbec4e 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -134,14 +134,22 @@ def isUcodeF3DEX3(F3D_VER: str) -> bool: return F3D_VER == "F3DEX3" -def is_ucode_point_lit(F3D_VER: str) -> bool: +def ucode_can_point_lit(F3D_VER: str) -> bool: + return isUcodeF3DEX2(F3D_VER) or ucode_always_point_lit(F3D_VER) + + +def ucode_always_point_lit(F3D_VER: str) -> bool: return F3D_VER in {"F3DEX3", "F3DZEX (AC)"} +def is_ucode_point_lit(F3D_VER: str, POINT_LIT_IF_SUPPORTED: bool) -> bool: + return ucode_always_point_lit(F3D_VER) or (ucode_can_point_lit(F3D_VER) and POINT_LIT_IF_SUPPORTED) + + class F3D: """NOTE: do not initialize this class manually! use get_F3D_GBI so that the single instance is cached from the microcode type.""" - def __init__(self, F3D_VER): + def __init__(self, F3D_VER, POINT_LIT_IF_SUPPORTED): self.F3D_VER = F3D_VER F3DEX_GBI = self.F3DEX_GBI = isUcodeF3DEX1(F3D_VER) F3DEX_GBI_2 = self.F3DEX_GBI_2 = isUcodeF3DEX2(F3D_VER) @@ -149,7 +157,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) F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" - F3D_POINT_LIT = self.F3D_POINT_LIT = is_ucode_point_lit(F3D_VER) + POINT_LIT_GBI = self.POINT_LIT_GBI = is_ucode_point_lit(F3D_VER, POINT_LIT_IF_SUPPORTED) # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -422,7 +430,7 @@ def __init__(self, F3D_VER): "G_DECAL_SPECIAL", "G_DECAL_ALL", } - if F3D_POINT_LIT: + if POINT_LIT_GBI: self.G_LIGHTING_POSITIONAL = 0x00400000 self.allGeomModeFlags.add("G_LIGHTING_POSITIONAL") @@ -1805,23 +1813,21 @@ def _DLHINTVALUE(self, count: int) -> int: return (self.G_INPUT_BUFFER_CMDS - remainderCommands) << 3 -g_F3D = { - "GBI": None, - "f3d_type": None, -} +g_F3D = {"GBI": None, "f3d_type": None, "point_lit": None} -def get_cached_F3D_GBI(f3d_type: str) -> F3D: +def get_cached_F3D_GBI(f3d_type: str, point_lit: bool) -> F3D: """Get constructed/cached F3D class""" - if g_F3D["GBI"] is None or f3d_type != g_F3D["f3d_type"]: + if g_F3D["GBI"] is None or f3d_type != g_F3D["f3d_type"] or point_lit != g_F3D["point_lit"]: g_F3D["f3d_type"] = f3d_type - g_F3D["GBI"] = F3D(f3d_type) + g_F3D["point_lit"] = point_lit + g_F3D["GBI"] = F3D(f3d_type, point_lit) return g_F3D["GBI"] def get_F3D_GBI() -> F3D: """Gets cached F3D class and automatically supplies params""" - return get_cached_F3D_GBI(bpy.context.scene.f3d_type) + return get_cached_F3D_GBI(bpy.context.scene.f3d_type, bpy.context.scene.fast64.settings.point_lit) def _SHIFTL(value, amount, mask): diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index c553f160b..c203f257d 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -30,7 +30,7 @@ from mathutils import Color from .f3d_enums import * -from .f3d_gbi import get_F3D_GBI, GBL_c1, GBL_c2, enumTexScroll, isUcodeF3DEX1, is_ucode_point_lit +from .f3d_gbi import get_F3D_GBI, GBL_c1, GBL_c2, enumTexScroll from .f3d_material_presets import * from ..utility import * from ..render_settings import Fast64RenderSettings_Properties, update_scene_props_from_render_settings @@ -443,10 +443,9 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c = c.column(align=True) return c - isF3DEX3 = bpy.context.scene.f3d_type == "F3DEX3" - is_f3dzex_ac = bpy.context.scene.f3d_type == "F3DZEX (AC)" - is_point_lit = is_ucode_point_lit(bpy.context.scene.f3d_type) - lightFxPrereq = isF3DEX3 and settings.g_lighting + f3d = get_F3D_GBI() + + lightFxPrereq = f3d.F3DEX_GBI_3 and settings.g_lighting ccWarnings = shadeInCC = False blendWarnings = shadeInBlender = zInBlender = False if isinstance(dataHolder, F3DMaterialProperty): @@ -464,11 +463,11 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if c is not None: if ccWarnings and not shadeInCC and not settings.g_tex_gen: c.label(text="Shade not used in CC, can disable lighting.", icon="INFO") - if isF3DEX3: + if f3d.F3DEX_GBI_3: c.prop(settings, "g_packed_normals") c.prop(settings, "g_lighting_specular") c.prop(settings, "g_ambocclusion") - elif is_point_lit: # Draw this flag in Not Useful for f3dex3 + elif f3d.POINT_LIT_GBI: # Draw this flag in Not Useful for f3dex3 c.prop(settings, "g_lighting_positional") d = indentGroup(c, "g_tex_gen", False) if d is not None: @@ -520,12 +519,12 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], elif blendWarnings and not shadeInBlender and settings.g_fog: c.label(text="Fog not used in rendermode / blender, can disable.", icon="INFO") - if is_f3dzex_ac: + if f3d.F3DZEX_AC_EXT: c = indentGroup(inputGroup, "Decals:", True) c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_equal") c.prop(settings, "g_decal_special") - elif isF3DEX3: + elif f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) c.prop(settings, "g_attroffset_st_enable") c.prop(settings, "g_attroffset_z_enable") @@ -556,9 +555,9 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c = indentGroup(inputGroup, "Not useful:", True) c.prop(settings, "g_lod") - if isUcodeF3DEX1(bpy.context.scene.f3d_type): + if f3d.F3DEX_GBI: c.prop(settings, "g_clipping") - elif isF3DEX3: + elif f3d.F3DEX_GBI_3: c.prop(settings, "g_lighting_positional") c.label(text="Always enabled in F3DEX3", icon="INFO") diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index bf17a1630..2a4f7fb9b 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -903,7 +903,7 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_decal_equal = value if bitFlags & self.f3d.G_DECAL_SPECIAL: rdp_settings.g_decal_special = value - if self.f3d.F3D_POINT_LIT: + if self.f3d.POINT_LIT_GBI: if bitFlags & self.f3d.G_LIGHTING_POSITIONAL: rdp_settings.g_lighting_positional = value if bitFlags & self.f3d.G_FOG: @@ -958,7 +958,7 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_gequal = False rdp_settings.g_equal = False rdp_settings.g_decal_special = False - if self.f3d.F3D_POINT_LIT: + if self.f3d.POINT_LIT_GBI: rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 else: rdp_settings.g_lighting_positional = False diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index e0f371e84..1b21d4b30 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -533,7 +533,9 @@ def writeAll( loadGfx = fMaterial.texture_DL f3d = fModel.f3d if self.loadPal: - savePaletteLoad(loadGfx, fPalette, self.palIndex, self.palFormat, self.palAddr, self.palLen, 5 - self.indexInMat, f3d) + savePaletteLoad( + loadGfx, fPalette, self.palIndex, self.palFormat, self.palAddr, self.palLen, 5 - self.indexInMat, f3d + ) if self.doTexLoad: saveTextureLoadOnly(fImage, loadGfx, self.texProp, None, 7 - self.indexInMat, self.texAddr, f3d) if self.doTexTile: @@ -625,7 +627,9 @@ def writeAll( # Determine how to arrange / load palette entries into upper half of tmem if self.isCI: assert self.ti0.useTex or self.ti1.useTex - if fModel.f3d.F3DZEX_AC_EXT: # TODO: This is kinda hacky, and the AC has palletes reserved for enviromental stuff apperantly? + if ( + fModel.f3d.F3DZEX_AC_EXT + ): # TODO: This is kinda hacky, and the AC has palletes reserved for enviromental stuff apperantly? if self.ti0.useTex: self.ti0.palIndex = 15 self.ti0.palLen = len(self.ti0.pal) @@ -1088,9 +1092,7 @@ def savePaletteLoad( palFmt = texFormatOf[palFormat] nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if f3d.F3DZEX_AC_EXT: - gfxOut.commands.append( - DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette) - ) + gfxOut.commands.append(DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette)) return gfxOut.commands.extend( [ diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 86a8dd649..0bee67bc8 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1621,7 +1621,8 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_shade, defaults.g_shade, "G_SHADE", *args) saveFunc(settings.g_cull_front, defaults.g_cull_front, "G_CULL_FRONT", *args) saveFunc(settings.g_cull_back, defaults.g_cull_back, "G_CULL_BACK", *args) - if bpy.context.scene.f3d_type == "F3DEX3": + f3d = get_F3D_GBI() + if f3d.F3DEX_GBI_3: saveFunc(settings.g_ambocclusion, defaults.g_ambocclusion, "G_AMBOCCLUSION", *args) saveFunc(settings.g_attroffset_z_enable, defaults.g_attroffset_z_enable, "G_ATTROFFSET_Z_ENABLE", *args) saveFunc(settings.g_attroffset_st_enable, defaults.g_attroffset_st_enable, "G_ATTROFFSET_ST_ENABLE", *args) @@ -1630,7 +1631,7 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_lighting_specular, defaults.g_lighting_specular, "G_LIGHTING_SPECULAR", *args) saveFunc(settings.g_fresnel_color, defaults.g_fresnel_color, "G_FRESNEL_COLOR", *args) saveFunc(settings.g_fresnel_alpha, defaults.g_fresnel_alpha, "G_FRESNEL_ALPHA", *args) - elif bpy.context.scene.f3d_type == "F3DZEX (AC)": + elif f3d.F3DZEX_AC_EXT: saveFunc(settings.g_decal_gequal, defaults.g_decal_gequal, "G_DECAL_GEQUAL", *args) saveFunc(settings.g_decal_equal, defaults.g_decal_equal, "G_DECAL_EQUAL", *args) saveFunc(settings.g_decal_special, defaults.g_decal_special, "G_DECAL_SPECIAL", *args) @@ -1640,9 +1641,9 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_tex_gen_linear, defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", *args) saveFunc(settings.g_lod, defaults.g_lod, "G_LOD", *args) saveFunc(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", *args) - if isUcodeF3DEX1(bpy.context.scene.f3d_type): + if f3d.F3DEX_GBI: saveFunc(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", *args) - if is_ucode_point_lit(bpy.context.scene.f3d_type): + if f3d.POINT_LIT_GBI: saveFunc(settings.g_lighting_positional, defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", *args) From 6d200a3bcbad86dd22a0745cff8e546b3bd6bfa4 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 12 Jun 2024 16:03:39 +0100 Subject: [PATCH 27/82] Removed useless check --- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 1b21d4b30..d7b87160e 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -776,7 +776,7 @@ def writeAll( fMaterial.texPaletteIndex = [self.ti0.palIndex, self.ti1.palIndex] self.ti0.palBaseName = self.ti0.getPaletteName() self.ti1.palBaseName = self.ti1.getPaletteName() - if not fModel.f3d.F3DZEX_AC_EXT and self.isCI and self.ti0.useTex and self.ti1.useTex and not self.ti1.loadPal: + if self.isCI and self.ti0.useTex and self.ti1.useTex and not self.ti1.loadPal: self.ti0.palBaseName = self.ti0.palBaseName + "_x_" + self.ti1.palBaseName self.ti1.pal = self.ti0.pal From ef25816b05081ffa36c0db55f8eafc479c0e66b8 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 13 Jun 2024 12:43:16 +0100 Subject: [PATCH 28/82] a --- fast64_internal/f3d/f3d_material.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 124e25b0a..b53cc45cc 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3006,13 +3006,13 @@ class RDPSettings(PropertyGroup): name="Greater or Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Render with a positive offset (closer to the camera) instead of the default negative offset", # TODO: Double check + description="F3DZEX (AC): Render with a positive offset (closer to the camera) instead of the default negative offset", ) g_decal_equal: bpy.props.BoolProperty( name="Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Render with no offset", # TODO: Double check + description="F3DZEX (AC): Render with no offset and the equal compare mode", ) g_decal_special: bpy.props.BoolProperty( name="Special", @@ -4021,8 +4021,8 @@ class F3DMaterialProperty(PropertyGroup): max=1, step=100.0 / 255.0, default=144.0 / 255.0, - update=update_node_values_with_preset, # TODO: This shouldnt need to actually interact with the nodes, maybe implement? - description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal.", + update=update_node_values_with_preset, + description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal", ) prim_color: bpy.props.FloatVectorProperty( name="Primitive Color", From 8e9b4703782410298b46b2bfc74f9ccc29ed2bb4 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 13 Jun 2024 14:31:40 +0100 Subject: [PATCH 29/82] raise if wrong pallete format --- fast64_internal/f3d/f3d_texture_writer.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index d7b87160e..a7afb558b 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -969,8 +969,8 @@ def saveTextureLoadOnly( # LoadTile will pad rows to 64 bit word alignment, while # LoadBlock assumes this is already done. - is_f3dzex_ac_ext = not f3d.F3DZEX_AC_EXT - useLoadBlock = canUseLoadBlock(fImage, texProp.tex_format, f3d) and is_f3dzex_ac_ext + needs_load = not f3d.F3DZEX_AC_EXT + useLoadBlock = canUseLoadBlock(fImage, texProp.tex_format, f3d) and needs_load line = 0 if useLoadBlock else getTileLine(fImage, SL, SH, siz, f3d) wid = 1 if useLoadBlock else fImage.width height = 1 if useLoadBlock else fImage.height @@ -981,7 +981,7 @@ def saveTextureLoadOnly( dxt = f3d.CALC_DXT_4b(fImage.width) siz = "G_IM_SIZ_16b" loadCommand = DPLoadBlock(loadtile, 0, 0, dxs, dxt) - elif is_f3dzex_ac_ext: + elif needs_load: sl2 = int(SL * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) sh2 = int(SH * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) siz = "G_IM_SIZ_8b" @@ -996,7 +996,7 @@ def saveTextureLoadOnly( dxt = f3d.CALC_DXT(fImage.width, f3d.G_IM_SIZ_VARS[siz + "_BYTES"]) siz += "_LOAD_BLOCK" loadCommand = DPLoadBlock(loadtile, 0, 0, dxs, dxt) - elif is_f3dzex_ac_ext: + elif needs_load: loadCommand = DPLoadTile(loadtile, sl, tl, sh, th) if not omitSetTextureImage: @@ -1004,7 +1004,7 @@ def saveTextureLoadOnly( gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, height, wid, fImage)) else: gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) - if is_f3dzex_ac_ext: + if needs_load: if not omitSetTile: gfxOut.commands.append(DPSetTile(fmt, siz, line, tmem, loadtile, 0, nocm, 0, 0, nocm, 0, 0)) gfxOut.commands.append(loadCommand) @@ -1053,7 +1053,7 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): - raise PluginError("Clamp + mirror not supported in F3DZEX (AC)\n") + raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" tileCommand = DPSetTile_Dolphin(fmt, rendertile, pal, wrap_s, wrap_t, shifts, shiftt) @@ -1092,6 +1092,8 @@ def savePaletteLoad( palFmt = texFormatOf[palFormat] nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if f3d.F3DZEX_AC_EXT: + if palFormat != "RGBA16": + raise PluginError("Only RGBA16 palette format supported in F3DZEX (AC)") gfxOut.commands.append(DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette)) return gfxOut.commands.extend( From 76d1b4b563e1192c1b4621b8f96c50b437074b1f Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 14 Jun 2024 16:47:40 +0100 Subject: [PATCH 30/82] =?UTF-8?q?I=20don=C2=B4t=20have=20a=20name=20for=20?= =?UTF-8?q?this=20pr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 2 ++ fast64_internal/f3d/f3d_gbi.py | 2 +- fast64_internal/f3d/f3d_material.py | 3 ++- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/__init__.py b/__init__.py index a5e500b9c..302b24c40 100644 --- a/__init__.py +++ b/__init__.py @@ -82,6 +82,8 @@ def draw(self, context): icon="INFO", ) col.prop(context.scene, "decomp_compatible", invert_checkbox=True, text="Homebrew Compatibility") + if context.scene.f3d_type == "F3DZEX (AC)": + col.box().label(text="Emu64 supports ignore texture restrictions!", icon="INFO") col.prop(context.scene, "ignoreTextureRestrictions") if context.scene.ignoreTextureRestrictions: col.box().label(text="Width/height must be < 1024. Must be png format.") diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 882dbec4e..a552acef7 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -5789,7 +5789,7 @@ def size(self, f3d): class DPLoadTLUT_Dolphin(GbiMacro): tlut_name: int count: int - unk: int # Always 1? + unk: int # Always 1? Possibly dropped support for ia16 addr: FImage def to_binary(self, f3d, segments): diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index b53cc45cc..e70cbbb32 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2766,7 +2766,8 @@ def ui_image( prop_split(prop_input, textureProp, "tex_format", name="Format") if textureProp.tex_format[:2] == "CI": prop_split(prop_input, textureProp, "ci_format", name="CI Format") - + if not bpy.context.scene.f3d_type != "F3DZEX (AC)" and textureProp.ci_format == "IA16": + multilineLabel(prop_input, text="IA16 not supported in F3DZEX (AC).\nWill export as a non color indexed", icon="ERROR") if not isLarge: if width > 0 and height > 0: texelsPerWord = 64 // texBitSizeInt[textureProp.tex_format] diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index a7afb558b..8744dba0f 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1053,7 +1053,7 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): - raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") + raise PluginError(f"In material {fMaterial.name}: Clamp + mirror not supported in F3DZEX (AC)") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" tileCommand = DPSetTile_Dolphin(fmt, rendertile, pal, wrap_s, wrap_t, shifts, shiftt) From 983c0ec26de9d4a9a97122fcc32767f510bea921 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 14 Jun 2024 17:47:35 +0100 Subject: [PATCH 31/82] Warnings --- fast64_internal/f3d/f3d_material.py | 52 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index e70cbbb32..5055ba7e4 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2703,6 +2703,7 @@ def ui_image( name: str, showCheckBox: bool, ): + is_fdzex_ac = bpy.context.scene.f3d_type == "F3DZEX (AC)" inputGroup = layout.box().column() inputGroup.prop( @@ -2766,25 +2767,22 @@ def ui_image( prop_split(prop_input, textureProp, "tex_format", name="Format") if textureProp.tex_format[:2] == "CI": prop_split(prop_input, textureProp, "ci_format", name="CI Format") - if not bpy.context.scene.f3d_type != "F3DZEX (AC)" and textureProp.ci_format == "IA16": - multilineLabel(prop_input, text="IA16 not supported in F3DZEX (AC).\nWill export as a non color indexed", icon="ERROR") + if is_fdzex_ac and textureProp.ci_format == "IA16": + multilineLabel( + prop_input, + text="IA16 not supported in F3DZEX (AC).\nWill export as a non color indexed", + icon="ERROR", + ) if not isLarge: + s, t = textureProp.S, textureProp.T 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.") - warnClampS = ( - not isPowerOf2(width) - and not textureProp.S.clamp - and (not textureProp.autoprop or textureProp.S.mask != 0) - ) - warnClampT = ( - not isPowerOf2(height) - and not textureProp.T.clamp - and (not textureProp.autoprop or textureProp.T.mask != 0) - ) + warnClampS = not isPowerOf2(width) and not s.clamp and (not textureProp.autoprop or s.mask != 0) + warnClampT = not isPowerOf2(height) and not t.clamp and (not textureProp.autoprop or 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") @@ -2792,31 +2790,37 @@ 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(s, "clamp", text="Clamp S") + clampSettings.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(s, "mirror", text="Mirror S") + mirrorSettings.prop(t, "mirror", text="Mirror T") + + if is_fdzex_ac and ((s.clamp and s.mirror) or (t.clamp and t.mirror)): + texFieldSettings.box().label( + text="Clamping + mirroring are not supported in F3DZEX (AC).", + icon="ERROR", + ) 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") - mask.prop(textureProp.T, "mask", text="Mask T") + mask.prop(s, "mask", text="Mask S") + mask.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(s, "shift", text="Shift S") + shift.prop(t, "shift", text="Shift T") low = prop_input.row() - low.prop(textureProp.S, "low", text="S Low") - low.prop(textureProp.T, "low", text="T Low") + low.prop(s, "low", text="S Low") + low.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(s, "high", text="S High") + high.prop(t, "high", text="T High") class CombinerProperty(PropertyGroup): From 34ac5fec7ed0a86e9fbfa2b576ecb3dcbee007c7 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 15 Jun 2024 09:03:29 +0100 Subject: [PATCH 32/82] Add todo --- 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 5055ba7e4..72921768c 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2770,7 +2770,7 @@ def ui_image( if is_fdzex_ac and textureProp.ci_format == "IA16": multilineLabel( prop_input, - text="IA16 not supported in F3DZEX (AC).\nWill export as a non color indexed", + text="IA16 not supported in F3DZEX (AC).", # TODO: Figure out a good fallback icon="ERROR", ) if not isLarge: From b448372917a40208d540f2e3927177107dd9023f Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 15 Jun 2024 09:38:33 +0100 Subject: [PATCH 33/82] This is unfortunately not valid handling errors in this is the biggest pain --- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 8744dba0f..a7afb558b 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1053,7 +1053,7 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): - raise PluginError(f"In material {fMaterial.name}: Clamp + mirror not supported in F3DZEX (AC)") + raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" tileCommand = DPSetTile_Dolphin(fmt, rendertile, pal, wrap_s, wrap_t, shifts, shiftt) From 4adf5824852ca5e4d205a53ef0af639c1cfa7a6f Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 15 Jun 2024 11:16:09 +0100 Subject: [PATCH 34/82] Only allow gequal with equal --- 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 72921768c..77a974a64 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -503,8 +503,9 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if f3d.F3DZEX_AC_EXT: c = indentGroup(inputGroup, "Decals:", True) - c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_equal") + if not settings.g_decal_equal: + c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_special") elif f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) From 4c20ed9760dbf075c85319c98d4d889220d9a11c Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 15 Jun 2024 11:26:31 +0100 Subject: [PATCH 35/82] Move tex adjust --- fast64_internal/f3d/f3d_gbi.py | 34 ++++++++++++++--------------- fast64_internal/f3d/f3d_material.py | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index a552acef7..8245507df 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4607,6 +4607,23 @@ def to_binary(self, f3d, segments): return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTFILT, 2, modeVal, f3d) +@dataclass(unsafe_hash=True) +class DPSetTextureAdjustMode(GbiMacro): + mode: str + + def to_binary(self, f3d, segments): + if f3d.F3DZEX_AC_EXT: + words = ( + _SHIFTL(f3d.G_SPECIAL_1, 24, 8) + | _SHIFTL(f3d.G_SPECIAL_TA_MODE, 16, 8) + | _SHIFTL(f3d.TA_ADJUST_MODE_VARS[mode], 0, 16), + 0, + ) + else: + raise PluginError("DPSetTextureAdjustMode only available in F3DZEX (AC).") + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + @dataclass(unsafe_hash=True) class DPSetTextureConvert(GbiMacro): # mode is a string @@ -5096,23 +5113,6 @@ def to_binary(self, f3d, segments): return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") -@dataclass(unsafe_hash=True) -class DPSetTextureAdjustMode(GbiMacro): - mode: str - - def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: - words = ( - _SHIFTL(f3d.G_SPECIAL_1, 24, 8) - | _SHIFTL(f3d.G_SPECIAL_TA_MODE, 16, 8) - | _SHIFTL(f3d.TA_ADJUST_MODE_VARS[mode], 0, 16), - 0, - ) - else: - raise PluginError("DPSetTextureAdjustMode only available in F3DZEX (AC).") - return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - - @dataclass(unsafe_hash=True) class DPLoadTile(GbiMacro): tile: int diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 77a974a64..144394385 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2771,7 +2771,7 @@ def ui_image( if is_fdzex_ac and textureProp.ci_format == "IA16": multilineLabel( prop_input, - text="IA16 not supported in F3DZEX (AC).", # TODO: Figure out a good fallback + text="IA16 not supported in F3DZEX (AC).", # TODO: Figure out a good fallback icon="ERROR", ) if not isLarge: From 6aaf842c590525339d8fd61a10b2c7c1d6438c03 Mon Sep 17 00:00:00 2001 From: Lila Date: Sat, 15 Jun 2024 16:48:51 +0100 Subject: [PATCH 36/82] set text adjust --- fast64_internal/f3d/f3d_enums.py | 5 +++++ fast64_internal/f3d/f3d_material.py | 25 ++++++++++++++++++++++--- fast64_internal/f3d/f3d_parser.py | 3 +++ fast64_internal/f3d/f3d_writer.py | 2 ++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 002e48892..8d2002e53 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -185,6 +185,11 @@ ("G_TF_BILERP", "Bilinear", "Standard N64 filtering with 3 point sample"), ] +enumTextAdjust = [ + ("G_TA_N64", "N64", "Center origin"), + ("G_TA_DOLPHIN", "Dolphin", "Top left"), +] + enumTextLUT = [ ("G_TT_NONE", "None", "None"), ("G_TT_RGBA16", "RGBA16", "RGBA16"), diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 144394385..bba25d204 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -605,16 +605,22 @@ def ui_other(settings, dataHolder, layout, useDropdown): if not useDropdown or dataHolder.menu_other: clipRatioGroup = inputGroup.column() prop_split(clipRatioGroup, settings, "clip_ratio", "Clip Ratio") - if isinstance(dataHolder, Material) or isinstance(dataHolder, F3DMaterialProperty): - blend_color_group = layout.row() + blend_color_group = inputGroup.row() prop_input_name = blend_color_group.column() prop_input = blend_color_group.column() prop_input_name.prop(dataHolder, "set_blend", text="Blend Color") prop_input.prop(dataHolder, "blend_color", text="") prop_input.enabled = dataHolder.set_blend if bpy.context.scene.f3d_type == "F3DZEX (AC)": - tex_edge_alpha_group = layout.column() + bilerp_text_adjust_row = inputGroup.row() + prop_input_name = bilerp_text_adjust_row.column() + prop_input = bilerp_text_adjust_row.column() + prop_input_name.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") + prop_input.prop(dataHolder, "bilerp_text_adjust", text="") + prop_input.enabled = dataHolder.set_bilerp_text_adjust + + tex_edge_alpha_group = inputGroup.column() tex_edge_alpha_row = tex_edge_alpha_group.row() prop_input_name = tex_edge_alpha_row.column() prop_input = tex_edge_alpha_row.column() @@ -3419,6 +3425,8 @@ def key(self): self.g_mdsft_zsrcsel, self.prim_depth.key() if prim else None, self.clip_ratio, + self.set_bilerp_text_adjust, + self.bilerp_text_adjust, self.set_rendermode, self.aa_en if setRM and rmAdv else None, self.z_cmp if setRM and rmAdv else None, @@ -3995,6 +4003,10 @@ class F3DMaterialProperty(PropertyGroup): default=False, update=update_node_values_with_preset, ) + set_bilerp_text_adjust: bpy.props.BoolProperty( + default=False, + update=update_node_values_with_preset, + ) set_key: bpy.props.BoolProperty( default=True, update=update_node_values_with_preset, @@ -4030,6 +4042,13 @@ class F3DMaterialProperty(PropertyGroup): update=update_node_values_with_preset, description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal", ) + bilerp_text_adjust: bpy.props.EnumProperty( + name="Bilerp Adjust Mode", + items=enumTextAdjust, + default="G_TA_N64", + update=update_node_values_without_preset, + description="F3DZEX (AC): Changes bilerp filter origin", + ) prim_color: bpy.props.FloatVectorProperty( name="Primitive Color", subtype="COLOR", diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 2a4f7fb9b..093178558 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -1721,6 +1721,9 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr elif command.name == "gsDPSetTexEdgeAlpha": # F3DEX (AC) mat.tex_edge_alpha = math_eval(command.params[0], self.f3d) / 255 mat.set_tex_edge_alpha = True + elif command.name == "gsDPSetTextureAdjustMode": + mat.bilerp_text_adjust = command.params[0] + mat.set_bilerp_text_adjust = True elif command.name == "gsDPSetFogColor": mat.fog_color = self.gammaInverseParam(command.params) mat.set_fog = True diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 9aaad2268..4ae984037 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1860,6 +1860,8 @@ def saveOtherDefinition(fMaterial, material, defaults): if bpy.context.scene.f3d_type == "F3DZEX (AC)": if material.set_tex_edge_alpha: fMaterial.mat_only_DL.commands.append(DPSetTexEdgeAlpha(int(material.tex_edge_alpha * 255))) + if material.set_bilerp_text_adjust: + fMaterial.mat_only_DL.commands.append(DPSetTextureAdjustMode(material.bilerp_text_adjust)) enumMatWriteMethod = [ From f573876cacb7304c87b0fbeefcef8e554b4a940c Mon Sep 17 00:00:00 2001 From: Lila Date: Mon, 17 Jun 2024 13:45:14 +0100 Subject: [PATCH 37/82] Incomplete implementation --- fast64_internal/f3d/f3d_gbi.py | 26 +++++++++++++++++----- fast64_internal/f3d/f3d_parser.py | 27 +++++++++++++++++++++++ fast64_internal/f3d/f3d_texture_writer.py | 2 +- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 8245507df..835645c80 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4843,8 +4843,8 @@ def to_binary(self, f3d, segments): image_ptr = int.from_bytes(encodeSegmentedAddr(self.image.startAddress, segments), "big") words = ( _SHIFTL(f3d.G_SETTIMG, 24, 8) - | _SHIFTL(self.fmt, 21, 3) - | _SHIFTL(self.siz, 19, 2) + | _SHIFTL(fmt, 21, 3) + | _SHIFTL(siz, 19, 2) | _SHIFTL(1, 18, 1) | _SHIFTL((self.height / 4) - 1, 10, 8) | _SHIFTL((self.width - 1), 0, 10), @@ -5168,7 +5168,7 @@ def is_LOADTILE(self, f3d): @dataclass(unsafe_hash=True) class DPSetTile_Dolphin(GbiMacro): - fmt: str + d_fmt: str # Always G_DOLPHIN_TLUT_DEFAULT_MODE (15)? tile: int name: int wrap_s: int @@ -5178,10 +5178,11 @@ class DPSetTile_Dolphin(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: + assert(self.d_fmt == f3d.G_DOLPHIN_TLUT_DEFAULT_MODE) words = ( ( _SHIFTL(f3d.G_SETTILE_DOLPHIN, 24, 8) - | _SHIFTL(f3d.G_IM_FMT_VARS[self.fmt], 20, 4) + | _SHIFTL(f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, 20, 4) | _SHIFTL(self.tile, 16, 3) | _SHIFTL(self.name, 12, 4) | _SHIFTL(f3d.GX_WRAP_MODE_VARS[self.wrap_s], 10, 2) @@ -5535,7 +5536,7 @@ def to_binary(self, f3d, segments): return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( f3d, segments ) + DPSetTile_Dolphin( - f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, 0, self.pal, self.ws, self.wt, self.ss, self.st + "G_DOLPHIN_TLUT_DEFAULT_MODE", 0, self.pal, self.ws, self.wt, self.ss, self.st ).to_binary( f3d, segments ) @@ -5707,17 +5708,30 @@ class DPLoadTextureTile_4b_Dolphin(GbiMacro): fmt: str width: int height: int + pal: int + ws: int + wt: int + ss: int + st: int def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( f3d, segments - ) + DPSetTile_Dolphin(f3d.G_DOLPHIN_TLUT_DEFAULT_MODE, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + ) + DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", 0, self.pal, self.ws, self.wt, self.ss, self.st).to_binary(f3d, segments) else: raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") + def to_c(self, static=True): + if static: + return f"gsDPLoadTextureTile_4b_Dolphin({', '.join( self.getargs(static) )})" + else: + assert not any((self.pal, self.ws, self.wt, self.ss, self.st)), "Static DPLoadTextureTile_4b_Dolphin does not support pal, ws, wt, ss, st being non zero" + return f"gDPLoadTextureTile_4b_Dolphin(glistp++, {', '.join( self.getargs(static)[:4] )})" + def size(self, f3d): return GFX_SIZE * 2 + # gsDPLoadMultiTile_4b diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 093178558..ce1f6a160 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -529,6 +529,8 @@ def initContext(self): self.numLights: int = 0 self.lightData: dict[Light, bpy.types.Object] = {} # Light : blender light object + self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + """ Restarts context, but keeps cached materials/textures. Warning: calls initContext, make sure to save/restore preserved fields @@ -1551,6 +1553,27 @@ def applyTLUT(self, image, tlut): if invalidIndicesDetected: print("Invalid LUT Indices detected.") + def load_dolphin_tlut(self, params): + tlut_name = math_eval(params[0], self.f3d) + # count = math_eval(params[1], self.f3d) # TODO: This should be passed in to the parse texture data function + texture_name = math_eval(params[3], self.f3d) + + self.ac_pal_dict[tlut_name] = texture_name + self.materialChanged = True + def set_texture_image_dolphin(self, params): + tileSettings = self.getTileSettings(0) + tileSettings.fmt = getTileFormat(params[0], self.f3d) + tileSettings.siz = getTileSize(params[1], self.f3d) + #height: int + #width: int + #image: FImage + def set_tile_size_dolphin(self, params): + pass + + def load_dolphin_4b_texture_block(self, params): + self.set_texture_image_dolphin(params) + self.set_tile_size_dolphin(params) + def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacro]"): callStack = [F3DParsedCommands(dlName, dlCommands, 0)] while len(callStack) > 0: @@ -1766,6 +1789,10 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr self.loadTile(command.params) elif command.name == "gsDPLoadTLUTCmd": self.loadTLUT(command.params, dlData) + elif command.name == "gsDPLoadTLUT_Dolphin": + self.load_dolphin_tlut(command.params) + elif command.name == "gsDPLoadTextureBlock_4b_Dolphin": + self.load_dolphin_4b_texture_block(command.params) # This all ignores S/T high/low values # This is pretty bad/confusing diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index a7afb558b..cebc53076 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1056,7 +1056,7 @@ def saveTextureTile( raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" - tileCommand = DPSetTile_Dolphin(fmt, rendertile, pal, wrap_s, wrap_t, shifts, shiftt) + tileCommand = DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", rendertile, pal, wrap_s, wrap_t, shifts, shiftt) tileSizeCommand = DPSetTileSize_Dolphin(rendertile, sl, tl, fImage.width, fImage.height) else: tileCommand = DPSetTile(fmt, siz, line, tmem, rendertile, pal, cmt, maskt, shiftt, cms, masks, shifts) From 41381e8f13d8a7707ffdf6f52cda7bb9be26aad1 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 10:28:17 +0100 Subject: [PATCH 38/82] Some attempts --- fast64_internal/f3d/f3d_gbi.py | 22 ++++++------ fast64_internal/f3d/f3d_parser.py | 59 ++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 835645c80..10ffd2456 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -4833,8 +4833,6 @@ class DPSetTextureImage_Dolphin(GbiMacro): height: int width: int image: FImage - # TODO: Should this use segmented to virtual? - # _segptrs = True # calls segmented_to_virtual on name when needed def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: @@ -5095,12 +5093,9 @@ class DPSetTileSize_Dolphin(GbiMacro): height: int def to_binary(self, f3d, segments): - # TODO: This is how emu64 converts n64 to dolphin - # u32 s_len = (settilesize->sh - settilesize->sl) / 4; - # u32 t_len = (settilesize->th - settilesize->tl) / 4; if f3d.F3DZEX_AC_EXT: words = ( - (_SHIFTL(G_SETTILESIZE, 24, 8) | _SHIFTL(self.s, 10, 14) | _SHIFTL(self.width - 1, 0, 10)), + (_SHIFTL(f3d.G_SETTILESIZE, 24, 8) | _SHIFTL(self.s, 10, 14) | _SHIFTL(self.width - 1, 0, 10)), ( _SHIFTL(1, 31, 1) | _SHIFTL(self.tile, 24, 3) @@ -5168,7 +5163,7 @@ def is_LOADTILE(self, f3d): @dataclass(unsafe_hash=True) class DPSetTile_Dolphin(GbiMacro): - d_fmt: str # Always G_DOLPHIN_TLUT_DEFAULT_MODE (15)? + d_fmt: str # Always G_DOLPHIN_TLUT_DEFAULT_MODE (15)? tile: int name: int wrap_s: int @@ -5178,7 +5173,7 @@ class DPSetTile_Dolphin(GbiMacro): def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: - assert(self.d_fmt == f3d.G_DOLPHIN_TLUT_DEFAULT_MODE) + assert self.d_fmt == f3d.G_DOLPHIN_TLUT_DEFAULT_MODE words = ( ( _SHIFTL(f3d.G_SETTILE_DOLPHIN, 24, 8) @@ -5718,7 +5713,11 @@ def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( f3d, segments - ) + DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", 0, self.pal, self.ws, self.wt, self.ss, self.st).to_binary(f3d, segments) + ) + DPSetTile_Dolphin( + "G_DOLPHIN_TLUT_DEFAULT_MODE", 0, self.pal, self.ws, self.wt, self.ss, self.st + ).to_binary( + f3d, segments + ) else: raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") @@ -5726,12 +5725,13 @@ def to_c(self, static=True): if static: return f"gsDPLoadTextureTile_4b_Dolphin({', '.join( self.getargs(static) )})" else: - assert not any((self.pal, self.ws, self.wt, self.ss, self.st)), "Static DPLoadTextureTile_4b_Dolphin does not support pal, ws, wt, ss, st being non zero" + assert not any( + (self.pal, self.ws, self.wt, self.ss, self.st) + ), "Static DPLoadTextureTile_4b_Dolphin does not support pal, ws, wt, ss, st being non zero" return f"gDPLoadTextureTile_4b_Dolphin(glistp++, {', '.join( self.getargs(static)[:4] )})" def size(self, f3d): return GFX_SIZE * 2 - # gsDPLoadMultiTile_4b diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index ce1f6a160..9c51da330 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -529,7 +529,11 @@ def initContext(self): self.numLights: int = 0 self.lightData: dict[Light, bpy.types.Object] = {} # Light : blender light object - self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) + self.texture_info: list[DPSetTextureImage_Dolphin] = [ + DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) for i in range(8) + ] """ Restarts context, but keeps cached materials/textures. @@ -596,6 +600,12 @@ def clearMaterial(self): self.lights.a = Ambient([0, 0, 0]) self.numLights = 0 + self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) + self.texture_info: list[DPSetTextureImage_Dolphin] = [ + DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) for i in range(8) + ] + mat.presetName = "Custom" def mat(self) -> F3DMaterialProperty: @@ -1553,27 +1563,42 @@ def applyTLUT(self, image, tlut): if invalidIndicesDetected: print("Invalid LUT Indices detected.") - def load_dolphin_tlut(self, params): + def load_dolphin_tlut(self, params): # gsDPLoadTLUT_Dolphin tlut_name = math_eval(params[0], self.f3d) - # count = math_eval(params[1], self.f3d) # TODO: This should be passed in to the parse texture data function - texture_name = math_eval(params[3], self.f3d) + self.ac_pal_dict[tlut_name] = params[3] + self.materialChanged = True - self.ac_pal_dict[tlut_name] = texture_name + def set_texture_image_dolphin(self, params): # DPSetTextureImage_Dolphin + self.set_img.fmt = getTileFormat(params[0], self.f3d) + self.set_img.siz = getTileSize(params[1], self.f3d) + self.set_img.height = math_eval(params[2], self.f3d) + self.set_img.width = math_eval(params[3], self.f3d) + self.set_img.image, self.currentTextureName = params[4] self.materialChanged = True - def set_texture_image_dolphin(self, params): - tileSettings = self.getTileSettings(0) - tileSettings.fmt = getTileFormat(params[0], self.f3d) - tileSettings.siz = getTileSize(params[1], self.f3d) - #height: int - #width: int - #image: FImage - def set_tile_size_dolphin(self, params): - pass - + + def set_tile_size_dolphin(self, params): # DPSetTileSize_Dolphin + tileSizeSettings = self.getTileSizeSettings(params[0]) + + dimensions = [0, 0, 0, 0] + for i in range(1, 5): + dimensions[i - 1] = math_eval(params[i], self.f3d) + + tileSizeSettings.uls = dimensions[0] + tileSizeSettings.ult = dimensions[1] + tileSizeSettings.lrs = dimensions[2] + tileSizeSettings.lrt = dimensions[3] + def load_dolphin_4b_texture_block(self, params): self.set_texture_image_dolphin(params) self.set_tile_size_dolphin(params) - + + def set_tile_dolphin(self, params): # DPSetTile_Dolphin + tile = self.getTileIndex(params[1]) + self.texture_info[tile] = self.set_img + tile_size: DPSetTileSize = self.tileSizes[tile] + tile_size.uls = 0 + tile_size.ult = 0 + def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacro]"): callStack = [F3DParsedCommands(dlName, dlCommands, 0)] while len(callStack) > 0: @@ -1789,6 +1814,8 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr self.loadTile(command.params) elif command.name == "gsDPLoadTLUTCmd": self.loadTLUT(command.params, dlData) + elif command.name == "gsDPSetTile_Dolphin": + self.set_tile_dolphin(command.params, dlData) elif command.name == "gsDPLoadTLUT_Dolphin": self.load_dolphin_tlut(command.params) elif command.name == "gsDPLoadTextureBlock_4b_Dolphin": From 1dfd0e9f966d317b153f0aeb413dd7c59de593cc Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 10:37:15 +0100 Subject: [PATCH 39/82] A --- fast64_internal/f3d/f3d_material.py | 4 ++-- fast64_internal/f3d/f3d_parser.py | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index bba25d204..21e7c1f08 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3425,8 +3425,6 @@ def key(self): self.g_mdsft_zsrcsel, self.prim_depth.key() if prim else None, self.clip_ratio, - self.set_bilerp_text_adjust, - self.bilerp_text_adjust, self.set_rendermode, self.aa_en if setRM and rmAdv else None, self.z_cmp if setRM and rmAdv else None, @@ -4322,6 +4320,7 @@ def key(self) -> F3DMaterialHash: self.use_default_lighting, self.set_blend, self.set_tex_edge_alpha, + self.set_bilerp_text_adjust, self.set_prim, self.set_env, self.set_key, @@ -4331,6 +4330,7 @@ def key(self) -> F3DMaterialHash: self.set_fog, tuple([round(value, 4) for value in self.blend_color]) if self.set_blend else None, round(self.tex_edge_alpha, 4) if self.set_tex_edge_alpha else None, + self.bilerp_text_adjust if self.set_bilerp_text_adjust else None, tuple([round(value, 4) for value in self.prim_color]) if self.set_prim else None, round(self.prim_lod_frac, 4) if self.set_prim else None, round(self.prim_lod_min, 4) if self.set_prim else None, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 9c51da330..69cbfdca2 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -963,12 +963,12 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_fresnel_color = False rdp_settings.g_fresnel_alpha = False if self.f3d.F3DZEX_AC_EXT: - rdp_settings.g_gequal = bitFlags & self.f3d.G_DECAL_GEQUAL != 0 - rdp_settings.g_equal = bitFlags & self.f3d.G_DECAL_EQUAL != 0 + rdp_settings.g_decal_gequal = bitFlags & self.f3d.G_DECAL_GEQUAL != 0 + rdp_settings.g_decal_equal = bitFlags & self.f3d.G_DECAL_EQUAL != 0 rdp_settings.g_decal_special = bitFlags & self.f3d.G_DECAL_SPECIAL != 0 else: - rdp_settings.g_gequal = False - rdp_settings.g_equal = False + rdp_settings.g_decal_gequal = False + rdp_settings.g_decal_equal = False rdp_settings.g_decal_special = False if self.f3d.POINT_LIT_GBI: rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 @@ -1623,7 +1623,14 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr self.addTriangle(command.params[0:3], dlData) elif command.name == "gsSP2Triangles": self.addTriangle(command.params[0:3] + command.params[4:7], dlData) - # TODO: Parse Animal Crossing's F3DZEX extended 5/7 bit tri commands + elif command.name == "gsSPNTrianglesInit_5b": + self.addTriangle(command.params[1:10], dlData) + elif command.name == "gsSPNTrianglesInit_7b": + self.addTriangle(command.params[1:7], dlData) + elif command.name == "gsSPNTriangles_5b": + self.addTriangle(command.params[1:12], dlData) + elif command.name == "gsSPNTriangles_7b": + self.addTriangle(command.params[1:9], dlData) elif command.name == "gsSPDisplayList" or command.name.startswith("gsSPBranch"): newDLName = self.processDLName(command.params[0]) if newDLName is not None: From d9e642434f818f1993bfb2ffd88e21a0a8c051a6 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 12:24:52 +0100 Subject: [PATCH 40/82] Parsing finished --- fast64_internal/f3d/f3d_bleed.py | 1 + fast64_internal/f3d/f3d_parser.py | 75 ++++++++++++++++++------------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 70c7971ce..a70df4ddb 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -456,6 +456,7 @@ def bleed_individual_cmd(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: in SPEndDisplayList, DPSetTextureImage, DPSetTextureImage_Dolphin, + DPSetTile_Dolphin, DPLoadBlock, DPLoadTile, DPLoadTLUTCmd, diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 69cbfdca2..4afdbf2e7 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -12,6 +12,7 @@ F3DMaterialProperty, update_node_values_of_material, F3DMaterialHash, + texBitSizeInt, ) from .f3d_writer import BufferVertex, F3DVert from ..utility import * @@ -531,9 +532,6 @@ def initContext(self): self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) - self.texture_info: list[DPSetTextureImage_Dolphin] = [ - DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) for i in range(8) - ] """ Restarts context, but keeps cached materials/textures. @@ -602,9 +600,6 @@ def clearMaterial(self): self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) - self.texture_info: list[DPSetTextureImage_Dolphin] = [ - DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) for i in range(8) - ] mat.presetName = "Custom" @@ -716,19 +711,11 @@ def addTriangle(self, indices, dlData): if self.materialChanged: region = None - tileSettings = self.tileSettings[0] - tileSizeSettings = self.tileSizes[0] - if tileSettings.tmem in self.tmemDict: - textureName = self.tmemDict[tileSettings.tmem] - self.loadTexture(dlData, textureName, region, tileSettings, False) - self.applyTileToMaterial(0, tileSettings, tileSizeSettings, dlData) - - tileSettings = self.tileSettings[1] - tileSizeSettings = self.tileSizes[1] - if tileSettings.tmem in self.tmemDict: - textureName = self.tmemDict[tileSettings.tmem] - self.loadTexture(dlData, textureName, region, tileSettings, False) - self.applyTileToMaterial(1, tileSettings, tileSizeSettings, dlData) + for tileSettings, tileSizeSettings in zip(self.tileSettings[:2], self.tileSizes[:2]): + if tileSettings.tmem in self.tmemDict: + textureName = self.tmemDict[tileSettings.tmem] + self.loadTexture(dlData, textureName, region, tileSettings, False) + self.applyTileToMaterial(tileSettings.tile, tileSettings, tileSizeSettings, dlData) self.applyLights() @@ -796,8 +783,11 @@ def applyTLUTToIndex(self, index): if texProp.tex_format[:2] == "CI": # Only handles TLUT at 256 - tlutName = self.tmemDict[256] - if 256 in self.tmemDict and tlutName is not None: + if self.f3d.F3DZEX_AC_EXT: + tlutName = self.ac_pal_dict.get(self.getTileSettings(index).palette, None) + else: + tlutName = self.tmemDict.get(256, None) + if tlutName is not None: tlut = self.textureData[tlutName] # print(f"TLUT: {tlutName}, {isinstance(tlut, F3DTextureReference)}") if isinstance(tlut, F3DTextureReference) or texProp.use_tex_reference: @@ -1565,7 +1555,8 @@ def applyTLUT(self, image, tlut): def load_dolphin_tlut(self, params): # gsDPLoadTLUT_Dolphin tlut_name = math_eval(params[0], self.f3d) - self.ac_pal_dict[tlut_name] = params[3] + texture_name = params[3] + self.ac_pal_dict[tlut_name] = texture_name self.materialChanged = True def set_texture_image_dolphin(self, params): # DPSetTextureImage_Dolphin @@ -1573,28 +1564,46 @@ def set_texture_image_dolphin(self, params): # DPSetTextureImage_Dolphin self.set_img.siz = getTileSize(params[1], self.f3d) self.set_img.height = math_eval(params[2], self.f3d) self.set_img.width = math_eval(params[3], self.f3d) - self.set_img.image, self.currentTextureName = params[4] + self.set_img.image = self.currentTextureName = params[4] self.materialChanged = True def set_tile_size_dolphin(self, params): # DPSetTileSize_Dolphin - tileSizeSettings = self.getTileSizeSettings(params[0]) + tile_size = self.getTileSizeSettings(params[0]) dimensions = [0, 0, 0, 0] for i in range(1, 5): dimensions[i - 1] = math_eval(params[i], self.f3d) - tileSizeSettings.uls = dimensions[0] - tileSizeSettings.ult = dimensions[1] - tileSizeSettings.lrs = dimensions[2] - tileSizeSettings.lrt = dimensions[3] + tile_size.uls = dimensions[0] + tile_size.ult = dimensions[1] + tile_size.lrs = dimensions[2] + tile_size.lrt = dimensions[3] - def load_dolphin_4b_texture_block(self, params): + def load_dolphin_4b_texture_block(self, params): # gsDPLoadTextureBlock_4b_Dolphin self.set_texture_image_dolphin(params) self.set_tile_size_dolphin(params) - def set_tile_dolphin(self, params): # DPSetTile_Dolphin + def set_tile_dolphin(self, params, dlData): # DPSetTile_Dolphin tile = self.getTileIndex(params[1]) - self.texture_info[tile] = self.set_img + tile_settings: DPSetTile = self.tileSettings[tile] + self.tmemDict[tile] = self.set_img.image + tile_settings.fmt = self.set_img.fmt + tile_settings.siz = self.set_img.siz + tile_settings.palette = math_eval(params[2], self.f3d) + + actual_fmt = tile_settings.fmt[8:].replace("_", "") + tile_settings.siz[8:-1].replace("_", "") + texelsPerWord = 64 // texBitSizeInt[actual_fmt] + assert self.set_img.width % texelsPerWord == 0 + tile_settings.line = self.set_img.width // texelsPerWord + + if tile_settings.palette in self.ac_pal_dict: + lut_tile_settings: DPSetTile = copy.copy(tile_settings) + lut_tile_settings.fmt = "G_IM_FMT_RGBA" + lut_tile_settings.siz = "G_IM_SIZ_16b" + tlut = self.loadTexture(dlData, self.ac_pal_dict[tile_settings.palette], [0, 0, 16, 16], lut_tile_settings, True) + + tile_settings.masks = log2iRoundUp(self.set_img.width) + tile_settings.maskt = log2iRoundUp(self.set_img.height) tile_size: DPSetTileSize = self.tileSizes[tile] tile_size.uls = 0 tile_size.ult = 0 @@ -1825,6 +1834,10 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr self.set_tile_dolphin(command.params, dlData) elif command.name == "gsDPLoadTLUT_Dolphin": self.load_dolphin_tlut(command.params) + elif command.name == "gsDPSetTextureImage_Dolphin": + self.set_texture_image_dolphin(command.params) + elif command.name == "gsDPSetTileSize_Dolphin": + self.set_tile_size_dolphin(command.params) elif command.name == "gsDPLoadTextureBlock_4b_Dolphin": self.load_dolphin_4b_texture_block(command.params) From 01ba260883f6f96a64b0c453ccaf9578ebbc5775 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 12:34:45 +0100 Subject: [PATCH 41/82] Non default mask --- fast64_internal/f3d/f3d_material.py | 6 +++++- fast64_internal/f3d/f3d_texture_writer.py | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 21e7c1f08..961044703 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2806,7 +2806,7 @@ def ui_image( if is_fdzex_ac and ((s.clamp and s.mirror) or (t.clamp and t.mirror)): texFieldSettings.box().label( - text="Clamping + mirroring are not supported in F3DZEX (AC).", + text="Clamp + mirror not supported in F3DZEX (AC).", icon="ERROR", ) @@ -2816,6 +2816,10 @@ def ui_image( mask = prop_input.row() mask.prop(s, "mask", text="Mask S") mask.prop(t, "mask", text="Mask T") + if is_fdzex_ac and (log2iRoundUp(width) != s.mask or log2iRoundUp(height) != t.mask): + prop_input.box().label( + text="Mask is not emulated in emu64, non default values are not supported",icon="ERROR", + ) shift = prop_input.row() shift.prop(s, "shift", text="Shift S") diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index cebc53076..d92e8163b 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1054,6 +1054,8 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") + if log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt: + raise PluginError("Mask is not emulated in emu64, non default values are not supported") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" tileCommand = DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", rendertile, pal, wrap_s, wrap_t, shifts, shiftt) From 0f07de09d320c3f2e394d79be11514300fde9248 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 12:43:53 +0100 Subject: [PATCH 42/82] use fmodel's gbi definition --- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index d92e8163b..90ce17580 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -206,7 +206,7 @@ def maybeSaveSingleLargeTextureSetup( sm = 2 if is4bit else 4 nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if curImgSet != i: - if f3d.F3DZEX_AC_EXT: + if fModel.f3d.F3DZEX_AC_EXT: gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, texDimensions[1], wid, fImage)) else: gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) From 6b9938cd323a2743faa195e654d5ec8eb4d1f6d8 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 13:41:14 +0100 Subject: [PATCH 43/82] =?UTF-8?q?Don=C2=B4t=20use=20image=20size=20for=20s?= =?UTF-8?q?len=20and=20tlen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fast64_internal/f3d/f3d_texture_writer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 90ce17580..5a5bb76d5 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1054,12 +1054,12 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") - if log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt: + if not tileSettings and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): raise PluginError("Mask is not emulated in emu64, non default values are not supported") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" tileCommand = DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", rendertile, pal, wrap_s, wrap_t, shifts, shiftt) - tileSizeCommand = DPSetTileSize_Dolphin(rendertile, sl, tl, fImage.width, fImage.height) + tileSizeCommand = DPSetTileSize_Dolphin(rendertile, sl, tl, (sh - sl) // 4 + 1, (th - tl) // 4 + 1) else: tileCommand = DPSetTile(fmt, siz, line, tmem, rendertile, pal, cmt, maskt, shiftt, cms, masks, shifts) tileSizeCommand = DPSetTileSize(rendertile, sl, tl, sh, th) From ebbd434960942f7ad696a01400a88ea68ab3b2d3 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 13:43:19 +0100 Subject: [PATCH 44/82] Remove a dumb mistake --- fast64_internal/f3d/f3d_gbi.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 10ffd2456..eb6915c8c 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -5699,37 +5699,23 @@ def size(self, f3d): @dataclass(unsafe_hash=True) class DPLoadTextureTile_4b_Dolphin(GbiMacro): - timg: FImage + img: FImage fmt: str width: int height: int - pal: int - ws: int - wt: int - ss: int - st: int def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: - return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( + return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.img).to_binary( f3d, segments ) + DPSetTile_Dolphin( - "G_DOLPHIN_TLUT_DEFAULT_MODE", 0, self.pal, self.ws, self.wt, self.ss, self.st + "G_DOLPHIN_TLUT_DEFAULT_MODE", 0, 0, 0, 0, 0, 0 ).to_binary( f3d, segments ) else: raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") - def to_c(self, static=True): - if static: - return f"gsDPLoadTextureTile_4b_Dolphin({', '.join( self.getargs(static) )})" - else: - assert not any( - (self.pal, self.ws, self.wt, self.ss, self.st) - ), "Static DPLoadTextureTile_4b_Dolphin does not support pal, ws, wt, ss, st being non zero" - return f"gDPLoadTextureTile_4b_Dolphin(glistp++, {', '.join( self.getargs(static)[:4] )})" - def size(self, f3d): return GFX_SIZE * 2 From 2596987acb590f971bab2c0eb4f93987db1a064b Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 14:10:23 +0100 Subject: [PATCH 45/82] Black format and move exception for pal format --- fast64_internal/f3d/f3d_gbi.py | 6 +----- fast64_internal/f3d/f3d_material.py | 3 ++- fast64_internal/f3d/f3d_parser.py | 6 ++++-- fast64_internal/f3d/f3d_texture_writer.py | 9 +++++++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index eb6915c8c..436855255 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -5708,11 +5708,7 @@ def to_binary(self, f3d, segments): if f3d.F3DZEX_AC_EXT: return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.img).to_binary( f3d, segments - ) + DPSetTile_Dolphin( - "G_DOLPHIN_TLUT_DEFAULT_MODE", 0, 0, 0, 0, 0, 0 - ).to_binary( - f3d, segments - ) + ) + DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) else: raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 961044703..3215c4aff 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2818,7 +2818,8 @@ def ui_image( mask.prop(t, "mask", text="Mask T") if is_fdzex_ac and (log2iRoundUp(width) != s.mask or log2iRoundUp(height) != t.mask): prop_input.box().label( - text="Mask is not emulated in emu64, non default values are not supported",icon="ERROR", + text="Mask is not emulated in emu64, non default values are not supported", + icon="ERROR", ) shift = prop_input.row() diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 4afdbf2e7..3bc4486a5 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -783,7 +783,7 @@ def applyTLUTToIndex(self, index): if texProp.tex_format[:2] == "CI": # Only handles TLUT at 256 - if self.f3d.F3DZEX_AC_EXT: + if self.f3d.F3DZEX_AC_EXT: tlutName = self.ac_pal_dict.get(self.getTileSettings(index).palette, None) else: tlutName = self.tmemDict.get(256, None) @@ -1600,7 +1600,9 @@ def set_tile_dolphin(self, params, dlData): # DPSetTile_Dolphin lut_tile_settings: DPSetTile = copy.copy(tile_settings) lut_tile_settings.fmt = "G_IM_FMT_RGBA" lut_tile_settings.siz = "G_IM_SIZ_16b" - tlut = self.loadTexture(dlData, self.ac_pal_dict[tile_settings.palette], [0, 0, 16, 16], lut_tile_settings, True) + tlut = self.loadTexture( + dlData, self.ac_pal_dict[tile_settings.palette], [0, 0, 16, 16], lut_tile_settings, True + ) tile_settings.masks = log2iRoundUp(self.set_img.width) tile_settings.maskt = log2iRoundUp(self.set_img.height) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 5a5bb76d5..9b625d130 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -638,6 +638,12 @@ def writeAll( self.ti1.palIndex = 14 self.ti1.palLen = len(self.ti1.pal) self.ti1.loadPal = True + if (self.ti0.useTex and self.ti0.palFormat != "RGBA16") or ( + self.ti1.useTex and self.ti1.palFormat != "RGBA16" + ): + raise PluginError( + f"In material {material.name}: Only RGBA16 palette format supported in F3DZEX (AC)" + ) elif not self.ti1.useTex: self.ti0.loadPal = True elif not self.ti0.useTex: @@ -1094,8 +1100,7 @@ def savePaletteLoad( palFmt = texFormatOf[palFormat] nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if f3d.F3DZEX_AC_EXT: - if palFormat != "RGBA16": - raise PluginError("Only RGBA16 palette format supported in F3DZEX (AC)") + assert palFormat == "RGBA16" gfxOut.commands.append(DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette)) return gfxOut.commands.extend( From 7d56247c3a7d20139efc0c425af6c1878c1cf4ff Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 14:19:54 +0100 Subject: [PATCH 46/82] check if pallete is not a reference --- fast64_internal/f3d/f3d_texture_writer.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 9b625d130..c9dd7dd66 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -630,17 +630,20 @@ def writeAll( if ( fModel.f3d.F3DZEX_AC_EXT ): # TODO: This is kinda hacky, and the AC has palletes reserved for enviromental stuff apperantly? + non_rgba = False if self.ti0.useTex: - self.ti0.palIndex = 15 - self.ti0.palLen = len(self.ti0.pal) - self.ti0.loadPal = True + if self.ti0.pal: + self.ti0.palIndex = 15 + self.ti0.palLen = len(self.ti0.pal) + self.ti0.loadPal = True + non_rgba = self.ti0.palFormat != "RGBA16" if self.ti1.useTex: - self.ti1.palIndex = 14 - self.ti1.palLen = len(self.ti1.pal) - self.ti1.loadPal = True - if (self.ti0.useTex and self.ti0.palFormat != "RGBA16") or ( - self.ti1.useTex and self.ti1.palFormat != "RGBA16" - ): + if self.ti1.pal: + self.ti1.palIndex = 14 + self.ti1.palLen = len(self.ti1.pal) + self.ti1.loadPal = True + non_rgba = self.ti1.palFormat != "RGBA16" + if non_rgba: raise PluginError( f"In material {material.name}: Only RGBA16 palette format supported in F3DZEX (AC)" ) From cc9be52c8fdc65adf0bfef431b45bcb8a421530f Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 14:25:17 +0100 Subject: [PATCH 47/82] Add comment to explain index choice --- fast64_internal/f3d/f3d_texture_writer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index c9dd7dd66..7cef49f45 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -633,13 +633,13 @@ def writeAll( non_rgba = False if self.ti0.useTex: if self.ti0.pal: - self.ti0.palIndex = 15 + self.ti0.palIndex = 15 # The default pallete index in AC is 15 self.ti0.palLen = len(self.ti0.pal) self.ti0.loadPal = True non_rgba = self.ti0.palFormat != "RGBA16" if self.ti1.useTex: if self.ti1.pal: - self.ti1.palIndex = 14 + self.ti1.palIndex = 15 - 1 self.ti1.palLen = len(self.ti1.pal) self.ti1.loadPal = True non_rgba = self.ti1.palFormat != "RGBA16" From 8ffe827530155b6d25b4095b8162a1cba0489ad7 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 15:29:03 +0100 Subject: [PATCH 48/82] use palette index --- fast64_internal/f3d/f3d_material.py | 21 ++++++++++++++++++++- fast64_internal/f3d/f3d_texture_writer.py | 9 ++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 3215c4aff..6c80d8ed2 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2635,6 +2635,14 @@ class TextureProperty(PropertyGroup): min=1, default=16, ) + use_pal_index: bpy.props.BoolProperty( + name="Palette Index Reference", description="F3DZEX (AC): Reference an already loaded palette" + ) + pal_index: bpy.props.StringProperty( + name="Palette Index", + default="0x03", + description="F3DZEX (AC): The palette's index. Defaults to the grass pallete index (3)", + ) menu: bpy.props.BoolProperty() tex_set: bpy.props.BoolProperty( @@ -2674,6 +2682,8 @@ def key(self): 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.use_pal_index if texSet and useRef and isCI else None, + self.pal_index if self.use_pal_index and texSet and useRef and isCI else None, ) @@ -2732,8 +2742,13 @@ 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": + if is_fdzex_ac: + row = prop_input.row() + row.prop(textureProp, "use_pal_index") + if textureProp.use_pal_index: + row.prop(textureProp, "pal_index", text="") flipbook = getattr(material.flipbookGroup, "flipbook" + texIndex) - if flipbook is None or not flipbook.enable: + if (not is_fdzex_ac or not textureProp.use_pal_index) and (flipbook is None or not flipbook.enable): prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") @@ -3652,6 +3667,8 @@ class AddPresetF3D(AddPresetBase, Operator): "f3d_mat.tex0.tex_reference_size", "f3d_mat.tex0.pal_reference", "f3d_mat.tex0.pal_reference_size", + "f3d_mat.tex0.use_pal_index", + "f3d_mat.tex0.pal_index", "f3d_mat.tex0.S", "f3d_mat.tex0.T", "f3d_mat.tex0.menu", @@ -3669,6 +3686,8 @@ class AddPresetF3D(AddPresetBase, Operator): "f3d_mat.tex1.tex_reference_size", "f3d_mat.tex1.pal_reference", "f3d_mat.tex1.pal_reference_size", + "f3d_mat.tex1.use_pal_index", + "f3d_mat.tex1.pal_index", "f3d_mat.tex1.S", "f3d_mat.tex1.T", "f3d_mat.tex1.menu", diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 7cef49f45..378ea3d26 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -480,7 +480,10 @@ def moreSetupFromModel( fMaterial, material, self.indexInMat ) if self.isTexRef: - if self.flipbook is not None: + if fModel.f3d.F3DZEX_AC_EXT and self.texProp.use_pal_index: + self.palLen = 16 if self.texFormat == "CI4" else 256 + self.palIndex = int(self.texProp.pal_index, 0) + elif self.flipbook is not None: self.palLen = len(self.pal) else: self.palLen = self.texProp.pal_reference_size @@ -633,7 +636,7 @@ def writeAll( non_rgba = False if self.ti0.useTex: if self.ti0.pal: - self.ti0.palIndex = 15 # The default pallete index in AC is 15 + self.ti0.palIndex = 15 # The default pallete index in AC is 15 self.ti0.palLen = len(self.ti0.pal) self.ti0.loadPal = True non_rgba = self.ti0.palFormat != "RGBA16" @@ -1063,7 +1066,7 @@ def saveTextureTile( if f3d.F3DZEX_AC_EXT: if (clamp_S and mirror_S) or (clamp_T and mirror_T): raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") - if not tileSettings and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): + if tileSettings and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): raise PluginError("Mask is not emulated in emu64, non default values are not supported") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT" From 8b4719418e41a90882aed4f7448227ae12d0d09c Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 15:29:52 +0100 Subject: [PATCH 49/82] Remove todo, this is a perfectly fine implementation thank you very much --- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 378ea3d26..a1e5b60d5 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -632,7 +632,7 @@ def writeAll( assert self.ti0.useTex or self.ti1.useTex if ( fModel.f3d.F3DZEX_AC_EXT - ): # TODO: This is kinda hacky, and the AC has palletes reserved for enviromental stuff apperantly? + ): non_rgba = False if self.ti0.useTex: if self.ti0.pal: From 3de697f84f01bca8e01886bb7d8058d5e420f00c Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 18 Jun 2024 15:32:06 +0100 Subject: [PATCH 50/82] Format before first review --- fast64_internal/f3d/f3d_texture_writer.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index a1e5b60d5..d51f358e8 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -630,9 +630,7 @@ def writeAll( # Determine how to arrange / load palette entries into upper half of tmem if self.isCI: assert self.ti0.useTex or self.ti1.useTex - if ( - fModel.f3d.F3DZEX_AC_EXT - ): + if fModel.f3d.F3DZEX_AC_EXT: non_rgba = False if self.ti0.useTex: if self.ti0.pal: From 0aa3f72cb94c6480055ea539a495117dc7d176ae Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:15:31 +0100 Subject: [PATCH 51/82] Made point lighting into a ucode version --- __init__.py | 7 ------- fast64_internal/f3d/f3d_enums.py | 7 ++++++- fast64_internal/f3d/f3d_gbi.py | 30 +++++++++++------------------- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/__init__.py b/__init__.py index 369ab3f12..de444a800 100644 --- a/__init__.py +++ b/__init__.py @@ -12,7 +12,6 @@ from .fast64_internal.oot.props_panel_main import OOT_ObjectProperties from .fast64_internal.utility_anim import utility_anim_register, utility_anim_unregister, ArmatureApplyWithMeshOperator -from .fast64_internal.f3d.f3d_gbi import isUcodeF3DEX2, ucode_can_point_lit, ucode_always_point_lit from .fast64_internal.f3d.f3d_material import mat_register, mat_unregister from .fast64_internal.f3d.f3d_render_engine import render_engine_register, render_engine_unregister from .fast64_internal.f3d.f3d_writer import f3d_writer_register, f3d_writer_unregister @@ -70,8 +69,6 @@ def draw(self, context): col.scale_y = 1.1 # extra padding fast64_settings = context.scene.fast64.settings prop_split(col, context.scene, "f3d_type", "F3D Microcode") - if ucode_can_point_lit(context.scene.f3d_type) and not ucode_always_point_lit(context.scene.f3d_type): - col.prop(fast64_settings, "point_lit") col.prop(context.scene, "saveTextures") col.prop(context.scene, "f3d_simple", text="Simple Material UI") col.prop(context.scene, "generateF3DNodeGraph", text="Generate F3D Node Graph For Materials") @@ -182,10 +179,6 @@ class Fast64Settings_Properties(bpy.types.PropertyGroup): name="Prefer RGBA Over CI", description="When enabled, fast64 will default colored textures's format to RGBA even if they fit CI requirements, with the exception of textures that would not fit into TMEM otherwise", ) - point_lit: bpy.props.BoolProperty( - name="Supports Point Ligthing", - description="When enabled, fast64 will export expecting a gbi that supports point lighting, such as Majora's Mask's ucode", - ) class Fast64_Properties(bpy.types.PropertyGroup): diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 8d2002e53..2738b714b 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -387,8 +387,13 @@ ("F3DEX/LX", "F3DEX/LX", "F3DEX version 1"), ("F3DLX.Rej", "F3DLX.Rej", "F3DLX.Rej"), ("F3DLP.Rej", "F3DLP.Rej", "F3DLP.Rej"), - ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT and MM"), + ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT"), ("F3DEX2.Rej/LX2.Rej", "F3DEX2.Rej/LX2.Rej", "Variant of F3DEX2 family using vertex rejection instead of clipping"), + ( + "F3DEX2/LX2 (Point Lit)", + "F3DEX2/LX2 (Point Lit)", + "Variant of F3DEX2 family with support for point lighting used in a few games including MM", + ), ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen"), ("F3DZEX (AC)", "F3DZEX (AC)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX"), ] diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index a04a71c1f..44428bb0a 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -68,6 +68,7 @@ class GfxMatWriteMethod(enum.Enum): "F3DLX.Rej": (64, 32), "F3DLP.Rej": (80, 32), "F3DEX2/LX2": (32, 32), + "F3DEX2/LX2 (Point Lit)": (32, 32), "F3DZEX (AC)": (32, 32), "F3DEX2.Rej/LX2.Rej": (64, 64), "F3DEX3": (56, 56), @@ -127,29 +128,21 @@ def isUcodeF3DEX1(F3D_VER: str) -> bool: def isUcodeF3DEX2(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DZEX (AC)"} + return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DEX2/LX2 (Point Lit)", "F3DZEX (AC)"} def isUcodeF3DEX3(F3D_VER: str) -> bool: return F3D_VER == "F3DEX3" -def ucode_can_point_lit(F3D_VER: str) -> bool: - return isUcodeF3DEX2(F3D_VER) or ucode_always_point_lit(F3D_VER) - - -def ucode_always_point_lit(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX3", "F3DZEX (AC)"} - - -def is_ucode_point_lit(F3D_VER: str, POINT_LIT_IF_SUPPORTED: bool) -> bool: - return ucode_always_point_lit(F3D_VER) or (ucode_can_point_lit(F3D_VER) and POINT_LIT_IF_SUPPORTED) +def is_ucode_point_lit(F3D_VER: str) -> bool: + return F3D_VER in {"F3DEX3", "F3DZEX (AC)", "F3DEX2/LX2 (Point Lit)"} class F3D: """NOTE: do not initialize this class manually! use get_F3D_GBI so that the single instance is cached from the microcode type.""" - def __init__(self, F3D_VER, POINT_LIT_IF_SUPPORTED): + def __init__(self, F3D_VER): self.F3D_VER = F3D_VER F3DEX_GBI = self.F3DEX_GBI = isUcodeF3DEX1(F3D_VER) F3DEX_GBI_2 = self.F3DEX_GBI_2 = isUcodeF3DEX2(F3D_VER) @@ -157,7 +150,7 @@ def __init__(self, F3D_VER, POINT_LIT_IF_SUPPORTED): F3DLP_GBI = self.F3DLP_GBI = self.F3DEX_GBI self.F3D_OLD_GBI = not (F3DEX_GBI or F3DEX_GBI_2 or F3DEX_GBI_3) F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" - POINT_LIT_GBI = self.POINT_LIT_GBI = is_ucode_point_lit(F3D_VER, POINT_LIT_IF_SUPPORTED) + POINT_LIT_GBI = self.POINT_LIT_GBI = is_ucode_point_lit(F3D_VER) # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 if F3DEX_GBI_2: @@ -1813,21 +1806,20 @@ def _DLHINTVALUE(self, count: int) -> int: return (self.G_INPUT_BUFFER_CMDS - remainderCommands) << 3 -g_F3D = {"GBI": None, "f3d_type": None, "point_lit": None} +g_F3D = {"GBI": None, "f3d_type": None} -def get_cached_F3D_GBI(f3d_type: str, point_lit: bool) -> F3D: +def get_cached_F3D_GBI(f3d_type: str) -> F3D: """Get constructed/cached F3D class""" - if g_F3D["GBI"] is None or f3d_type != g_F3D["f3d_type"] or point_lit != g_F3D["point_lit"]: + if g_F3D["GBI"] is None or f3d_type != g_F3D["f3d_type"]: g_F3D["f3d_type"] = f3d_type - g_F3D["point_lit"] = point_lit - g_F3D["GBI"] = F3D(f3d_type, point_lit) + g_F3D["GBI"] = F3D(f3d_type) return g_F3D["GBI"] def get_F3D_GBI() -> F3D: """Gets cached F3D class and automatically supplies params""" - return get_cached_F3D_GBI(bpy.context.scene.f3d_type, bpy.context.scene.fast64.settings.point_lit) + return get_cached_F3D_GBI(bpy.context.scene.f3d_type) def _SHIFTL(value, amount, mask): From 89ae555aab9e82be68e3deda49cc7e50cb43f0f8 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:16:46 +0100 Subject: [PATCH 52/82] IA16 is uncommon enough that this is probably not worth it --- fast64_internal/f3d/f3d_material.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index b3f6edbbe..edc71d2a2 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -2790,11 +2790,7 @@ def ui_image( if textureProp.tex_format[:2] == "CI": prop_split(prop_input, textureProp, "ci_format", name="CI Format") if is_fdzex_ac and textureProp.ci_format == "IA16": - multilineLabel( - prop_input, - text="IA16 not supported in F3DZEX (AC).", # TODO: Figure out a good fallback - icon="ERROR", - ) + multilineLabel(prop_input, text="IA16 not supported in F3DZEX (AC).", icon="ERROR") if not isLarge: s, t = textureProp.S, textureProp.T if width > 0 and height > 0: From b165e9cd2f76e44a6913771de5349efd5f6c00ab Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:19:35 +0100 Subject: [PATCH 53/82] Small typo --- fast64_internal/f3d/f3d_gbi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 44428bb0a..f7e66b8ea 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -354,7 +354,7 @@ def __init__(self, F3D_VER): self.G_DECAL_LEQUAL = 0x00000000 self.G_DECAL_GEQUAL = 0x00000010 self.G_DECAL_EQUAL = 0x00000020 - self.G_DECAL_ALWAYS = self.G_DECAL_GEQUAL | self.G_DECAL_LEQUAL + self.G_DECAL_ALWAYS = self.G_DECAL_GEQUAL | self.G_DECAL_EQUAL self.G_DECAL_SPECIAL = 0x00000040 self.G_DECAL_ALL = self.G_DECAL_ALWAYS | self.G_DECAL_SPECIAL self.G_TLUT_DOLPHIN = 2 From 08d89c96e87702663780fc76037e4f1a475613f7 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:24:07 +0100 Subject: [PATCH 54/82] Remove a leftover --- __init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/__init__.py b/__init__.py index de444a800..484189098 100644 --- a/__init__.py +++ b/__init__.py @@ -67,7 +67,6 @@ def poll(cls, context): def draw(self, context): col = self.layout.column() col.scale_y = 1.1 # extra padding - fast64_settings = context.scene.fast64.settings prop_split(col, context.scene, "f3d_type", "F3D Microcode") col.prop(context.scene, "saveTextures") col.prop(context.scene, "f3d_simple", text="Simple Material UI") From 9516aed8294e7c4a8d05dc3182c25a143b1054cf Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:24:52 +0100 Subject: [PATCH 55/82] And a merge conflict mistake --- __init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/__init__.py b/__init__.py index 484189098..5880496a3 100644 --- a/__init__.py +++ b/__init__.py @@ -78,7 +78,6 @@ def draw(self, context): "While inlining, all meshes will be restored to world default values.\n You can configure these values in the world properties tab.", icon="INFO", ) - col.prop(context.scene, "decomp_compatible", invert_checkbox=True, text="Homebrew Compatibility") if context.scene.f3d_type == "F3DZEX (AC)": col.box().label(text="Emu64 supports ignore texture restrictions!", icon="INFO") col.prop(context.scene, "ignoreTextureRestrictions") From 534b31e5e2a156df95d3c6e32ef4bedfd68c8574 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:56:44 +0100 Subject: [PATCH 56/82] Improved decal geo modes --- fast64_internal/f3d/f3d_material.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index edc71d2a2..866ce34dc 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -503,9 +503,10 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if f3d.F3DZEX_AC_EXT: c = indentGroup(inputGroup, "Decals:", True) + if blendWarnings and settings.zmode != "ZMODE_DEC": + c.label(text="Non-decal rendermode / blender, these will be ignored.", icon="INFO") c.prop(settings, "g_decal_equal") - if not settings.g_decal_equal: - c.prop(settings, "g_decal_gequal") + c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_special") elif f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) @@ -3030,23 +3031,25 @@ class RDPSettings(PropertyGroup): description="F3DEX3: Enables offsets to vertex ST values, usually for UV scrolling", ) # AC Decal Modes - g_decal_gequal: bpy.props.BoolProperty( - name="Greater or Equal", + g_decal_equal: bpy.props.BoolProperty( + name="Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Render with a positive offset (closer to the camera) instead of the default negative offset", + description="F3DZEX (AC): Disables any offset and uses the equal compare mode", ) - g_decal_equal: bpy.props.BoolProperty( - name="Equal", + g_decal_gequal: bpy.props.BoolProperty( + name="Greater or Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Render with no offset and the equal compare mode", + description="F3DZEX (AC): When enabled, the greater or equal compare mode is used, " + "if Equal is disabled a positive offset is also used (closer to the camera).\n" + "When disabled, the default negative offset and less or equal compare mode are used.", ) g_decal_special: bpy.props.BoolProperty( name="Special", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): ", # TODO: Write description + description="F3DZEX (AC): Apropriately sets decal blend modes", ) # v1/2 difference g_cull_front: bpy.props.BoolProperty( From 73919810a113138b5f8e48adec37438e719a9b2a Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 20:57:42 +0100 Subject: [PATCH 57/82] Extra dot in description removed --- 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 866ce34dc..53db80bd8 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3043,7 +3043,7 @@ class RDPSettings(PropertyGroup): update=update_node_values_with_preset, description="F3DZEX (AC): When enabled, the greater or equal compare mode is used, " "if Equal is disabled a positive offset is also used (closer to the camera).\n" - "When disabled, the default negative offset and less or equal compare mode are used.", + "When disabled, the default negative offset and less or equal compare mode are used", ) g_decal_special: bpy.props.BoolProperty( name="Special", From 732cf4cd680b79277a0213d028a0cbc2c8718d2f Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 21:17:57 +0100 Subject: [PATCH 58/82] Give the user more info --- fast64_internal/f3d/f3d_material.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 53db80bd8..812eac797 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -503,11 +503,30 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if f3d.F3DZEX_AC_EXT: c = indentGroup(inputGroup, "Decals:", True) - if blendWarnings and settings.zmode != "ZMODE_DEC": - c.label(text="Non-decal rendermode / blender, these will be ignored.", icon="INFO") c.prop(settings, "g_decal_equal") c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_special") + # These decal modes are not as clear as others, so we give the user a bit more info + if not settings.g_decal_equal and not settings.g_decal_gequal: + compare_mode = "GX_LEQUAL" + elif settings.g_decal_gequal and not settings.g_decal_equal: + compare_mode = "GX_GEQUAL" + elif settings.g_decal_equal and not settings.g_decal_gequal: + compare_mode = "GX_EQUAL" + else: + compare_mode = "GX_ALWAYS" + decal_mode_info = f"Compare mode = {compare_mode}" + if not settings.g_decal_equal: + decal_mode_info += "\nDepth offset " + ("towards" if settings.g_decal_gequal else "away from") + " the camera" + if settings.g_decal_special: + decal_mode_info += "\nBlend mode: " + if settings.g_decal_gequal: + decal_mode_info += "GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_NOOP" + else: + decal_mode_info += "GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA, GX_LO_NOOP" + if blendWarnings and settings.zmode != "ZMODE_DEC": + decal_mode_info = "Non-decal rendermode / blender, these will be ignored." + multilineLabel(c, decal_mode_info, icon="INFO") elif f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) c.prop(settings, "g_attroffset_st_enable") From 3fb8faf847b2c42faa395c63f9a2a5551dbd4f9a Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 21:18:51 +0100 Subject: [PATCH 59/82] black format --- fast64_internal/f3d/f3d_material.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 812eac797..bc0b68770 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -516,14 +516,19 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], else: compare_mode = "GX_ALWAYS" decal_mode_info = f"Compare mode = {compare_mode}" + if not settings.g_decal_equal: - decal_mode_info += "\nDepth offset " + ("towards" if settings.g_decal_gequal else "away from") + " the camera" + decal_mode_info += ( + "\nDepth offset " + ("towards" if settings.g_decal_gequal else "away from") + " the camera" + ) + if settings.g_decal_special: decal_mode_info += "\nBlend mode: " if settings.g_decal_gequal: decal_mode_info += "GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_NOOP" else: decal_mode_info += "GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA, GX_LO_NOOP" + if blendWarnings and settings.zmode != "ZMODE_DEC": decal_mode_info = "Non-decal rendermode / blender, these will be ignored." multilineLabel(c, decal_mode_info, icon="INFO") From fe88346e4398fb3fa140750343994742c5a43777 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 19 Jun 2024 21:30:30 +0100 Subject: [PATCH 60/82] Change : to =, update order --- fast64_internal/f3d/f3d_material.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index bc0b68770..0e7e70535 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -517,18 +517,18 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], compare_mode = "GX_ALWAYS" decal_mode_info = f"Compare mode = {compare_mode}" - if not settings.g_decal_equal: - decal_mode_info += ( - "\nDepth offset " + ("towards" if settings.g_decal_gequal else "away from") + " the camera" - ) - if settings.g_decal_special: - decal_mode_info += "\nBlend mode: " + decal_mode_info += "\nBlend mode = " if settings.g_decal_gequal: decal_mode_info += "GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_NOOP" else: decal_mode_info += "GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA, GX_LO_NOOP" + if not settings.g_decal_equal: + decal_mode_info += ( + "\nDepth offset " + ("towards" if settings.g_decal_gequal else "away from") + " the camera" + ) + if blendWarnings and settings.zmode != "ZMODE_DEC": decal_mode_info = "Non-decal rendermode / blender, these will be ignored." multilineLabel(c, decal_mode_info, icon="INFO") From a7f219f3187fa07ecfc5061e5ed35872b5aa9b4f Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 20 Jun 2024 10:48:07 +0100 Subject: [PATCH 61/82] Only warn if being set, add warning for adjust mode --- fast64_internal/f3d/f3d_material.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 0e7e70535..3678125dc 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -644,6 +644,8 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input_name.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") prop_input.prop(dataHolder, "bilerp_text_adjust", text="") prop_input.enabled = dataHolder.set_bilerp_text_adjust + if dataHolder.set_bilerp_text_adjust and settings.g_mdsft_text_filt != "G_TF_BILERP": + bilerp_text_adjust_row.label(text="Material is not recognised as Bilerp", icon="INFO") tex_edge_alpha_group = inputGroup.column() tex_edge_alpha_row = tex_edge_alpha_group.row() @@ -652,7 +654,7 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input_name.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") prop_input.prop(dataHolder, "tex_edge_alpha", text="") prop_input.enabled = dataHolder.set_tex_edge_alpha - if not settings.is_emu64_texedge: + if dataHolder.set_tex_edge_alpha and not settings.is_emu64_texedge: tex_edge_alpha_group.label(text="Material is not recognised as Tex Edge", icon="INFO") From f5e284f986dcf96a135c2125f95f5178106e75c3 Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 20 Jun 2024 11:01:05 +0100 Subject: [PATCH 62/82] Last change Made code cleaner and easier to read, updated warnings, added seperator and a new line before the f3dzex ac logic --- fast64_internal/f3d/f3d_material.py | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 3678125dc..bc215e4a9 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -637,25 +637,26 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input_name.prop(dataHolder, "set_blend", text="Blend Color") prop_input.prop(dataHolder, "blend_color", text="") prop_input.enabled = dataHolder.set_blend + if bpy.context.scene.f3d_type == "F3DZEX (AC)": - bilerp_text_adjust_row = inputGroup.row() - prop_input_name = bilerp_text_adjust_row.column() - prop_input = bilerp_text_adjust_row.column() - prop_input_name.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") - prop_input.prop(dataHolder, "bilerp_text_adjust", text="") - prop_input.enabled = dataHolder.set_bilerp_text_adjust + inputGroup.separator() + adjust_group = inputGroup.column() + adjust_row = adjust_group.row() + adjust_row.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") + prop_value = adjust_row.column() + prop_value.enabled = dataHolder.set_bilerp_text_adjust + prop_value.prop(dataHolder, "bilerp_text_adjust", text="") if dataHolder.set_bilerp_text_adjust and settings.g_mdsft_text_filt != "G_TF_BILERP": - bilerp_text_adjust_row.label(text="Material is not recognised as Bilerp", icon="INFO") - - tex_edge_alpha_group = inputGroup.column() - tex_edge_alpha_row = tex_edge_alpha_group.row() - prop_input_name = tex_edge_alpha_row.column() - prop_input = tex_edge_alpha_row.column() - prop_input_name.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") - prop_input.prop(dataHolder, "tex_edge_alpha", text="") - prop_input.enabled = dataHolder.set_tex_edge_alpha + adjust_group.label(text="Texture filter is not bilerp.", icon="INFO") + + alpha_group = inputGroup.column() + alpha_row = alpha_group.row() + alpha_row.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") + prop_value = alpha_row.column() + prop_value.enabled = dataHolder.set_tex_edge_alpha + prop_value.prop(dataHolder, "tex_edge_alpha", text="") if dataHolder.set_tex_edge_alpha and not settings.is_emu64_texedge: - tex_edge_alpha_group.label(text="Material is not recognised as Tex Edge", icon="INFO") + alpha_group.label(text="Render mode is not recognised as tex edge.", icon="INFO") def tmemUsageUI(layout, textureProp): From cff265120e5f80150f5883ce7dc76c7ec1b9059a Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 20 Jun 2024 11:09:47 +0100 Subject: [PATCH 63/82] No need to group alpha and adjust as inputGroup is already a col --- fast64_internal/f3d/f3d_material.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index bc215e4a9..c934c2e95 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -640,23 +640,21 @@ def ui_other(settings, dataHolder, layout, useDropdown): if bpy.context.scene.f3d_type == "F3DZEX (AC)": inputGroup.separator() - adjust_group = inputGroup.column() - adjust_row = adjust_group.row() + adjust_row = inputGroup.row() adjust_row.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") prop_value = adjust_row.column() prop_value.enabled = dataHolder.set_bilerp_text_adjust prop_value.prop(dataHolder, "bilerp_text_adjust", text="") if dataHolder.set_bilerp_text_adjust and settings.g_mdsft_text_filt != "G_TF_BILERP": - adjust_group.label(text="Texture filter is not bilerp.", icon="INFO") + inputGroup.label(text="Texture filter is not bilerp.", icon="INFO") - alpha_group = inputGroup.column() - alpha_row = alpha_group.row() + alpha_row = inputGroup.row() alpha_row.prop(dataHolder, "set_tex_edge_alpha", text="Tex Edge Alpha") prop_value = alpha_row.column() prop_value.enabled = dataHolder.set_tex_edge_alpha prop_value.prop(dataHolder, "tex_edge_alpha", text="") if dataHolder.set_tex_edge_alpha and not settings.is_emu64_texedge: - alpha_group.label(text="Render mode is not recognised as tex edge.", icon="INFO") + inputGroup.label(text="Render mode is not recognised as tex edge.", icon="INFO") def tmemUsageUI(layout, textureProp): From 08f916e46d38b64224d77cb5e758fdb4c226ee4d Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 30 Jun 2024 21:29:24 +0100 Subject: [PATCH 64/82] Undo accidental change --- fast64_internal/f3d/f3d_gbi.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index f7e66b8ea..a21d03b23 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -1806,7 +1806,10 @@ def _DLHINTVALUE(self, count: int) -> int: return (self.G_INPUT_BUFFER_CMDS - remainderCommands) << 3 -g_F3D = {"GBI": None, "f3d_type": None} +g_F3D = { + "GBI": None, + "f3d_type": None, +} def get_cached_F3D_GBI(f3d_type: str) -> F3D: From 99e6fd2b709279572a6fd5acf006378bbea8f55d Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 19 Jul 2024 13:24:29 +0100 Subject: [PATCH 65/82] black format --- fast64_internal/f3d/f3d_material.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 562dca93c..496c7f1e5 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -3570,7 +3570,7 @@ def is_emu64_texedge(self): and self.cvg_dst == "CVG_DST_CLAMP" and self.zmode == "ZMODE_OPA" ) - + @property def is_emu64_texedge(self): return ( @@ -3626,8 +3626,9 @@ def attributes_from_dict(self, data: dict, info: dict): ("decalEqual", "g_decal_equal", False), ("decalSpecial", "g_decal_special", False), ] - geo_mode_attributes = (geo_mode_all_attributes + geo_mode_f3dex_attributes + geo_mode_f3dex3_attributes + geo_mode_f3dzex_ac_attributes -) + geo_mode_attributes = ( + geo_mode_all_attributes + geo_mode_f3dex_attributes + geo_mode_f3dex3_attributes + geo_mode_f3dzex_ac_attributes + ) def geo_mode_to_dict(self, f3d=None): f3d = f3d if f3d else get_F3D_GBI() From 56e224911fe4217c18cb024f658db52e875f1089 Mon Sep 17 00:00:00 2001 From: Lila Date: Fri, 19 Jul 2024 13:27:36 +0100 Subject: [PATCH 66/82] remove blender from info --- 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 496c7f1e5..878fdb7d0 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -531,7 +531,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], ) if blendWarnings and settings.zmode != "ZMODE_DEC": - decal_mode_info = "Non-decal rendermode / blender, these will be ignored." + decal_mode_info = "Non-decal rendermode, these will be ignored." multilineLabel(c, decal_mode_info, icon="INFO") elif f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) From c0b6701fd62bf546ccac0c3fbcecd42443d33d2a Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 09:18:03 +0100 Subject: [PATCH 67/82] Fixed naming and parsing issues --- fast64_internal/f3d/f3d_bleed.py | 8 ++++---- fast64_internal/f3d/f3d_gbi.py | 8 ++++---- fast64_internal/f3d/f3d_parser.py | 16 ++++++++++++---- fast64_internal/f3d/f3d_writer.py | 4 ++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index a70df4ddb..7f8fc5cdf 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -18,9 +18,9 @@ SPLineW3D, SP2Triangles, SPNTrianglesInit_5b, - SP5bitTriangles, + SPNTriangles_5b, SPNTrianglesInit_7b, - SP7bitTriangles, + SPNTriangles_7b, SPCullDisplayList, SPSegment, SPBranchLessZraw, @@ -62,9 +62,9 @@ SPLine3D, SPLineW3D, SPNTrianglesInit_5b, - SP5bitTriangles, + SPNTriangles_5b, SPNTrianglesInit_7b, - SP7bitTriangles, + SPNTriangles_7b, ] diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 224c5b869..9df6d1228 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3779,7 +3779,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class SP5bitTriangles(GbiMacro): +class SPNTriangles_5b(GbiMacro): v0: int v1: int v2: int @@ -3804,7 +3804,7 @@ def to_binary(self, f3d, segments): | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), ) else: - raise PluginError("SP5bitTriangles only available in F3DZEX (AC).") + raise PluginError("SPNTriangles_5b only available in F3DZEX (AC).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -3837,7 +3837,7 @@ def to_binary(self, f3d, segments): @dataclass(unsafe_hash=True) -class SP7bitTriangles(GbiMacro): +class SPNTriangles_7b(GbiMacro): v0: int v1: int v2: int @@ -3862,7 +3862,7 @@ def to_binary(self, f3d, segments): ), ) else: - raise PluginError("SP7bitTriangles only available in F3DZEX (AC).") + raise PluginError("SPNTriangles_7b only available in F3DZEX (AC).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 22d2236ab..966be5098 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -532,6 +532,7 @@ def initContext(self): self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) + self.tri_init_count = 0 """ Restarts context, but keeps cached materials/textures. @@ -600,6 +601,7 @@ def clearMaterial(self): self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) + self.tri_init_count = 0 mat.presetName = "Custom" @@ -1635,13 +1637,19 @@ def processCommands(self, dlData: str, dlName: str, dlCommands: "list[ParsedMacr elif command.name == "gsSP2Triangles": self.addTriangle(command.params[0:3] + command.params[4:7], dlData) elif command.name == "gsSPNTrianglesInit_5b": - self.addTriangle(command.params[1:10], dlData) + self.tri_init_count = math_eval(command.params[0], self.f3d) + self.addTriangle(command.params[1 : max(10, self.tri_init_count)], dlData) + self.tri_init_count -= 3 elif command.name == "gsSPNTrianglesInit_7b": - self.addTriangle(command.params[1:7], dlData) + self.tri_init_count = math_eval(command.params[0], self.f3d) + self.addTriangle(command.params[1 : max(7, self.tri_init_count)], dlData) + self.tri_init_count -= 2 elif command.name == "gsSPNTriangles_5b": - self.addTriangle(command.params[1:12], dlData) + self.addTriangle(command.params[0 : max(12, self.tri_init_count * 3)], dlData) + self.tri_init_count -= 4 elif command.name == "gsSPNTriangles_7b": - self.addTriangle(command.params[1:9], dlData) + self.addTriangle(command.params[0 : max(9, self.tri_init_count * 3)], dlData) + self.tri_init_count -= 3 elif command.name == "gsSPDisplayList" or command.name.startswith("gsSPBranch"): newDLName = self.processDLName(command.params[0]) if newDLName is not None: diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 63d688fc9..e844c617d 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1250,10 +1250,10 @@ def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data commands.append(SPNTrianglesInit_5b(tri_5_bit_len, *get_n_tris_indices(triangles, t, 3))) t += 3 while t < tri_5_bit_len: - commands.append(SP5bitTriangles(*get_n_tris_indices(triangles, t, 4))) + commands.append(SPNTriangles_5b(*get_n_tris_indices(triangles, t, 4))) t += 4 if left == 3: - commands.append(SPNTrianglesInit_5b(left, *get_n_tris_indices(triangles, t, 3))) + commands.append(SPNTriangles_7b(left, *get_n_tris_indices(triangles, t, 3))) elif left > 0: commands.append(SPNTrianglesInit_7b(left, *get_n_tris_indices(triangles, t, 2))) return commands From 5455be965520c028780036e29ccabd3698126a93 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 09:37:09 +0100 Subject: [PATCH 68/82] add comment remover utility function --- fast64_internal/f3d/f3d_parser.py | 2 +- fast64_internal/utility.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 966be5098..4711d4774 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -2390,7 +2390,7 @@ def importMeshC( f3dContext.mat().draw_layer.oot = drawLayer transformMatrix = mathutils.Matrix.Scale(1 / scale, 4) - parseF3D(data, name, transformMatrix, name, name, "oot", drawLayer, f3dContext, True) + parseF3D(comment_remover(data), name, transformMatrix, name, name, "oot", drawLayer, f3dContext, True) f3dContext.createMesh(obj, removeDoubles, importNormals, callClearMaterial) applyRotation([obj], math.radians(-90), "X") diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 45aac222b..0bbd11888 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1762,3 +1762,16 @@ def json_to_prop_group(prop_group, data: dict, blacklist: list[str] = None, whit default.from_dict(data.get(prop, None)) else: setattr(prop_group, prop, data.get(prop, default)) + + +def comment_remover(text): + # https://stackoverflow.com/a/241506 + def replacer(match): + s = match.group(0) + if s.startswith("/"): + return " " # note: a space and not an empty string + else: + return s + + pattern = re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE) + return re.sub(pattern, replacer, text) From 31160018a84461700999bf9f1421a6cfc5fc0688 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 09:41:52 +0100 Subject: [PATCH 69/82] Update f3d_material.py --- 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 24f08efbc..ea576ba0a 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -483,7 +483,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], else: shadeAlphaLabel = "Vtx alpha" c = indentGroup(inputGroup, f"Shade alpha = {shadeAlphaLabel}:", True) - if isF3DEX3: + if f3d.F3DEX_GBI_3: lighting_group = c.column(align=True) lighting_group.enabled = settings.g_lighting or not disable_dependent lighting_group.prop(settings, "g_lighttoalpha") From 019dd1e3ce02fc666d50774ff0368361c9afa45e Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 20:36:10 +0100 Subject: [PATCH 70/82] Fix writer (forgot to change the arguments) also clean up the logic --- fast64_internal/f3d/f3d_writer.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index e844c617d..0fdb4e30e 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1243,19 +1243,16 @@ def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data t = 0 if triConverterInfo.f3d.F3DZEX_AC_EXT: left = (len(triangles) - 3) % 4 - tri_5_bit_len = len(triangles) - left if len(triangles) <= 2: commands.append(SPNTrianglesInit_7b(len(triangles), *get_n_tris_indices(triangles, t, 2))) return commands - commands.append(SPNTrianglesInit_5b(tri_5_bit_len, *get_n_tris_indices(triangles, t, 3))) + commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, t, 3))) t += 3 - while t < tri_5_bit_len: + while t + 4 < len(triangles): commands.append(SPNTriangles_5b(*get_n_tris_indices(triangles, t, 4))) t += 4 - if left == 3: - commands.append(SPNTriangles_7b(left, *get_n_tris_indices(triangles, t, 3))) - elif left > 0: - commands.append(SPNTrianglesInit_7b(left, *get_n_tris_indices(triangles, t, 2))) + if left > 0: + commands.append(SPNTriangles_7b(*get_n_tris_indices(triangles, t, 3))) return commands while t < len(triangles): From 86f3a6f0be365147a9a8bc6e2280fb5fb8f21e84 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 21:51:59 +0100 Subject: [PATCH 71/82] pick best tri format per vertex load --- __init__.py | 5 +++ fast64_internal/f3d/f3d_enums.py | 10 +++++ fast64_internal/f3d/f3d_gbi.py | 2 +- fast64_internal/f3d/f3d_writer.py | 64 ++++++++++++++++++------------- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/__init__.py b/__init__.py index 3d04eace3..a967e5437 100644 --- a/__init__.py +++ b/__init__.py @@ -28,6 +28,7 @@ mat_unregister, check_or_ask_color_management, ) +from .fast64_internal.f3d.f3d_enums import enum_ac_tri_type from .fast64_internal.f3d.f3d_render_engine import render_engine_register, render_engine_unregister from .fast64_internal.f3d.f3d_writer import f3d_writer_register, f3d_writer_unregister from .fast64_internal.f3d.f3d_parser import f3d_parser_register, f3d_parser_unregister @@ -83,6 +84,8 @@ def draw(self, context): col = self.layout.column() col.scale_y = 1.1 # extra padding prop_split(col, context.scene, "f3d_type", "F3D Microcode") + if context.scene.f3d_type == "F3DZEX (AC)": + prop_split(col, context.scene.fast64.settings, "ac_tri_type", "Triangle Export Type") col.prop(context.scene, "saveTextures") col.prop(context.scene, "f3d_simple", text="Simple Material UI") col.prop(context.scene, "exportInlineF3D", text="Bleed and Inline Material Exports") @@ -196,6 +199,8 @@ class Fast64Settings_Properties(bpy.types.PropertyGroup): name="Prefer RGBA Over CI", description="When enabled, fast64 will default colored textures's format to RGBA even if they fit CI requirements, with the exception of textures that would not fit into TMEM otherwise", ) + ac_tri_type: bpy.props.EnumProperty(name="Triangle Export Type", items=enum_ac_tri_type) + dont_ask_color_management: bpy.props.BoolProperty(name="Don't ask to set color management properties") repo_settings_tab: bpy.props.BoolProperty(default=True, name="Repo Settings") diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 2738b714b..49e894ae5 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -444,3 +444,13 @@ ("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"), ] + +enum_ac_tri_type = [ + ( + "Auto", + "Auto", + "Pick between 5b and 7b commands depending on triangle count, 7b can access more of the vertex buffer, 5b has smaller commands", + ), + ("5b", "5 Bit", "Always use 5b commands"), + ("7b", "7 Bit", "Always use 5b commands"), +] diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 9df6d1228..dc1e68868 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -69,7 +69,7 @@ class GfxMatWriteMethod(enum.Enum): "F3DLP.Rej": (80, 32), "F3DEX2/LX2": (32, 32), "F3DEX2/LX2 (Point Lit)": (32, 32), - "F3DZEX (AC)": (32, 32), + "F3DZEX (AC)": (2**7, 32), "F3DEX2.Rej/LX2.Rej": (64, 64), "F3DEX3": (56, 56), } diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 0fdb4e30e..8b7298ed0 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -936,7 +936,7 @@ def getSortedBuffer(self) -> dict[int, list[BufferVertex]]: return limbVerts - def processGeometry(self): + def processGeometry(self, ac_use_7b=False): # Sort verts by limb index, then load current limb verts bufferStart = self.bufferStart bufferEnd = self.bufferStart @@ -996,7 +996,7 @@ def processGeometry(self): bufferStart = bufferEnd # Load triangles - triCmds = createTriangleCommands(self.vertexBufferTriangles, self.vertBuffer, self.triConverterInfo) + triCmds = createTriangleCommands(self.vertexBufferTriangles, self.vertBuffer, ac_use_7b, self.triConverterInfo) if not self.triConverterInfo.f3d.F3DEX_GBI_3 or not self.material.f3d_mat.use_cel_shading: self.triList.commands.extend(triCmds) else: @@ -1123,6 +1123,16 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional # Disable alpha compare culling for future DLs self.triList.commands.append(SPAlphaCompareCull("G_ALPHA_COMPARE_CULL_DISABLE", 0)) + def get_best_load_size_and_tri_type(self, vertices_up_next: int): + if self.triConverterInfo.f3d.F3DZEX_AC_EXT: + setting = bpy.context.scene.fast64.settings.ac_tri_type + if (setting == "Auto" and vertices_up_next > 2**5) or setting == "7b": + return True, 2**7 + else: + return False, 2**5 + else: + return False, self.triConverterInfo.f3d.vert_load_size + def addFace(self, face, stOffset): triIndices = [] addedVerts = [] # verts added to existing vertexBuffer @@ -1146,10 +1156,11 @@ def addFace(self, face, stOffset): if bufferVert not in self.vertBuffer[: self.bufferStart]: allVerts.append(bufferVert) + ac_use_7b, vert_load_size = self.get_best_load_size_and_tri_type(len(self.vertBuffer) + len(addedVerts)) # We care only about load size, since loading is what takes up time. # Even if vert_buffer is larger, its still another load to fill it. - if len(self.vertBuffer) + len(addedVerts) > self.triConverterInfo.f3d.vert_load_size: - self.processGeometry() + if len(self.vertBuffer) + len(addedVerts) > vert_load_size: + self.processGeometry(ac_use_7b) self.vertBuffer = self.vertBuffer[: self.bufferStart] + allVerts self.vertexBufferTriangles = [triIndices] else: @@ -1158,7 +1169,8 @@ def addFace(self, face, stOffset): def finish(self, terminateDL): if len(self.vertexBufferTriangles) > 0: - self.processGeometry() + ac_use_7b, _vert_load_size = self.get_best_load_size_and_tri_type(len(self.vertBuffer)) + self.processGeometry(ac_use_7b) # if self.originalGroupIndex != self.currentGroupIndex: # self.triList.commands.append(SPMatrix(getMatrixAddrFromGroup(self.originalGroupIndex), "G_MTX_LOAD")) @@ -1225,34 +1237,34 @@ def getLoopColor(loop: bpy.types.MeshLoop, mesh: bpy.types.Mesh) -> Vector: return mathutils.Vector((normalizedRGB[0], normalizedRGB[1], normalizedRGB[2], normalizedA)) -def createTriangleCommands(triangles, vertexBuffer, triConverterInfo): +def createTriangleCommands(triangles, vertexBuffer, ac_use_7b, triConverterInfo): triangles = copy.deepcopy(triangles) commands = [] def getIndices(*tris): return [vertexBuffer.index(v) for tri in tris for v in tri] - def get_n_tris_indices(triangles: list, i: int, n: int): # Includes dummy data to fill out the command - if len(triangles) - i >= n: - return getIndices(*triangles[i : i + n]) - indices = getIndices(*triangles[i:]) - while len(indices) < n * 3: - indices.extend((0, 0, 0)) - return indices - - t = 0 if triConverterInfo.f3d.F3DZEX_AC_EXT: - left = (len(triangles) - 3) % 4 - if len(triangles) <= 2: - commands.append(SPNTrianglesInit_7b(len(triangles), *get_n_tris_indices(triangles, t, 2))) - return commands - commands.append(SPNTrianglesInit_5b(len(triangles), *get_n_tris_indices(triangles, t, 3))) - t += 3 - while t + 4 < len(triangles): - commands.append(SPNTriangles_5b(*get_n_tris_indices(triangles, t, 4))) - t += 4 - if left > 0: - commands.append(SPNTriangles_7b(*get_n_tris_indices(triangles, t, 3))) + + def get_n_tris_indices(n: int, tri_index=0, triangles=triangles): # Includes dummy data to fill out the command + if len(triangles) - tri_index >= n: + return getIndices(*triangles[tri_index : tri_index + n]), tri_index + n + indices = getIndices(*triangles[tri_index:]) + while len(indices) < n * 3: + indices.extend((0, 0, 0)) + return indices, tri_index + n + + tris, tri_index = get_n_tris_indices(2 if ac_use_7b else 3) + if ac_use_7b: + commands.append(SPNTrianglesInit_7b(len(triangles), *tris)) + else: + commands.append(SPNTrianglesInit_5b(len(triangles), *tris)) + + n = 3 if ac_use_7b else 4 + while tri_index < len(triangles): + tris, tri_index = get_n_tris_indices(n, tri_index) + commands.append(SPNTriangles_7b(*tris) if ac_use_7b else SPNTriangles_5b(*tris)) + return commands while t < len(triangles): From cdcab91a74898d4c815bbaa9e5d469e7b5f1f3f0 Mon Sep 17 00:00:00 2001 From: Lila Date: Tue, 30 Jul 2024 21:55:33 +0100 Subject: [PATCH 72/82] typo and reduce shortening --- fast64_internal/f3d/f3d_enums.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 49e894ae5..afa1d06ff 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -449,8 +449,8 @@ ( "Auto", "Auto", - "Pick between 5b and 7b commands depending on triangle count, 7b can access more of the vertex buffer, 5b has smaller commands", + "Pick between 5 bit and 7 bit commands depending on triangle count, 7 bit can access more of the vertex buffer, 5 bit has smaller commands", ), - ("5b", "5 Bit", "Always use 5b commands"), - ("7b", "7 Bit", "Always use 5b commands"), + ("5b", "5 Bit", "Always use 5 bit commands"), + ("7b", "7 Bit", "Always use 7 bit commands"), ] From ddd6bec0e2e85e07e046e4d45300b1057c02e4de Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 4 Aug 2024 08:29:36 +0100 Subject: [PATCH 73/82] Texture and palette fixes --- fast64_internal/f3d/f3d_gbi.py | 22 ++++++++++--------- fast64_internal/f3d/f3d_texture_writer.py | 26 +++++++++++------------ fast64_internal/utility.py | 8 +++++++ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index dc1e68868..629e89fdb 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -2648,9 +2648,9 @@ def to_c_textures(self, texCSeparate, savePNG, texDir, texArrayBitSize): data = CData() for _, fImage in self.textures.items(): if savePNG: - data.append(fImage.to_c_tex_separate(texDir, texArrayBitSize)) + data.append(fImage.to_c_tex_separate(texDir, texArrayBitSize, self.f3d)) else: - data.append(fImage.to_c(texArrayBitSize)) + data.append(fImage.to_c(texArrayBitSize, self.f3d)) return data def to_c_materials(self, gfxFormatter): @@ -3311,20 +3311,22 @@ def size(self): def to_binary(self): return self.data - def to_c(self, texArrayBitSize): - return self.to_c_helper(self.to_c_data(texArrayBitSize), texArrayBitSize) + def to_c(self, texArrayBitSize, f3d): + return self.to_c_helper(self.to_c_data(texArrayBitSize), texArrayBitSize, f3d) - def to_c_tex_separate(self, texPath, texArrayBitSize): - return self.to_c_helper('#include "' + texPath + self.filename + '"', texArrayBitSize) + def to_c_tex_separate(self, texPath, texArrayBitSize, f3d): + return self.to_c_helper('#include "' + texPath + self.filename + '"', texArrayBitSize, f3d) - def to_c_helper(self, texData, bitsPerValue): + def to_c_helper(self, texData, bitsPerValue, f3d): code = CData() code.header = f"extern u{str(bitsPerValue)} {self.name}[];\n" - # This is to force 8 byte alignment - if bitsPerValue != 64: + if bitsPerValue != 64 and not f3d.F3DZEX_AC_EXT: # This is to force 8 byte alignment code.source = f"Gfx {self.name}_aligner[] = {{gsSPEndDisplayList()}};\n" - code.source += f"u{str(bitsPerValue)} {self.name}[] = {{\n\t" + code.source += f"u{str(bitsPerValue)} {self.name}[] " + if f3d.F3DZEX_AC_EXT: # Emu64 requires 32 BYTE alignments + code.source += "__attribute__((aligned(32))) " + code.source += "= {\n\t" code.source += texData code.source += "\n};\n\n" return code diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index d51f358e8..bcd6f951c 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -489,7 +489,7 @@ def moreSetupFromModel( self.palLen = self.texProp.pal_reference_size else: assert self.flipbook is None - self.pal = getColorsUsedInImage(self.texProp.tex, self.palFormat) + self.pal = getColorsUsedInImage(self.texProp.tex, self.palFormat, fModel.f3d.F3DZEX_AC_EXT) self.palLen = len(self.pal) if self.palLen > (16 if self.texFormat == "CI4" else 256): raise PluginError( @@ -559,7 +559,9 @@ def writeAll( fModel.writeTexRefNonCITextures(self.flipbook, self.texFormat) else: if self.isTexCI: - writeCITextureData(self.texProp.tex, fImage, self.pal, self.palFormat, self.texFormat) + writeCITextureData( + self.texProp.tex, fImage, self.pal, self.palFormat, self.texFormat, f3d.F3DZEX_AC_EXT + ) else: writeNonCITextureData(self.texProp.tex, fImage, self.texFormat) @@ -1119,12 +1121,12 @@ def savePaletteLoad( # Functions for converting and writing texture and palette data -def extractConvertCIPixel(image, pixels, i, j, palFormat): +def extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb): color = [1, 1, 1, 1] for field in range(image.channels): color[field] = pixels[(j * image.size[0] + i) * image.channels + field] if palFormat == "RGBA16": - pixelColor = getRGBA16Tuple(color) + pixelColor = get_rgb5a3_color(color) if use_argb else getRGBA16Tuple(color) elif palFormat == "IA16": pixelColor = getIA16Tuple(color) else: @@ -1132,13 +1134,13 @@ def extractConvertCIPixel(image, pixels, i, j, palFormat): return pixelColor -def getColorsUsedInImage(image, palFormat): +def getColorsUsedInImage(image, palFormat, use_argb): palette = [] # N64 is -Y, Blender is +Y pixels = image.pixels[:] for j in reversed(range(image.size[1])): for i in range(image.size[0]): - pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat) + pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb) if pixelColor not in palette: palette.append(pixelColor) return palette @@ -1152,13 +1154,13 @@ def mergePalettes(pal0, pal1): return palette -def getColorIndicesOfTexture(image, palette, palFormat): +def getColorIndicesOfTexture(image, palette, palFormat, use_argb): texture = [] # N64 is -Y, Blender is +Y pixels = image.pixels[:] for j in reversed(range(image.size[1])): for i in range(image.size[0]): - pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat) + pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb) if pixelColor not in palette: raise PluginError(f"Bug: {image.name} palette len {len(palette)} missing CI") texture.append(palette.index(pixelColor)) @@ -1186,16 +1188,12 @@ def writePaletteData(fPalette: FImage, palette: list[int]): def writeCITextureData( - image: bpy.types.Image, - fImage: FImage, - palette: list[int], - palFmt: str, - texFmt: str, + image: bpy.types.Image, fImage: FImage, palette: list[int], palFmt: str, texFmt: str, use_argb: bool ): if fImage.converted: return - texture = getColorIndicesOfTexture(image, palette, palFmt) + texture = getColorIndicesOfTexture(image, palette, palFmt, use_argb) if texFmt == "CI4": fImage.data = compactNibbleArray(texture, image.size[0], image.size[1]) diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index ee1bb0b28..718d14fce 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -571,6 +571,14 @@ def getRGBA16Tuple(color): ) +def get_rgb5a3_color(color): + r, g, b, a = round(color[0] * 255), round(color[1] * 255), round(color[2] * 255), round(color[3] * 255) + if a == 255: # Opaque, upper bit is 1 + return (1 << 15) | ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) + else: + return ((a >> 5) << 12) | ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4) + + RGB_TO_LUM_COEF = mathutils.Vector([0.2126729, 0.7151522, 0.0721750]) From f90b4c066116e66869c5c0481d2d6397ba420efa Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 4 Aug 2024 08:32:34 +0100 Subject: [PATCH 74/82] Add tri_index --- fast64_internal/f3d/f3d_writer.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 8b7298ed0..68601d0eb 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1267,13 +1267,16 @@ def get_n_tris_indices(n: int, tri_index=0, triangles=triangles): # Includes du return commands - while t < len(triangles): - if not triConverterInfo.f3d.F3D_OLD_GBI and t + 1 < len(triangles): - commands.append(SP2Triangles(*getIndices(triangles[t]), 0, *getIndices(triangles[t + 1]), 0)) - t += 2 + tri_index = 0 + while tri_index < len(triangles): + if not triConverterInfo.f3d.F3D_OLD_GBI and tri_index + 1 < len(triangles): + commands.append( + SP2Triangles(*getIndices(triangles[tri_index]), 0, *getIndices(triangles[tri_index + 1]), 0) + ) + tri_index += 2 else: - commands.append(SP1Triangle(*getIndices(triangles[t]), 0)) - t += 1 + commands.append(SP1Triangle(*getIndices(triangles[tri_index]), 0)) + tri_index += 1 return commands From a098b283c90b10fa06dc181a25aed058686ed0a4 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 7 Aug 2024 12:03:29 +0100 Subject: [PATCH 75/82] rename decal modes to geo modes --- 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 a4456992d..51e2b9c73 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -509,7 +509,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c.prop(settings, "g_decal_equal") c.prop(settings, "g_decal_gequal") c.prop(settings, "g_decal_special") - # These decal modes are not as clear as others, so we give the user a bit more info + # These geo modes are not as clear as others, so we give the user a bit more info if not settings.g_decal_equal and not settings.g_decal_gequal: compare_mode = "GX_LEQUAL" elif settings.g_decal_gequal and not settings.g_decal_equal: From b0ed0490f3f0b3d8c9b6a8cd05e9e17037e59d87 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 7 Aug 2024 13:03:14 +0100 Subject: [PATCH 76/82] Rename ucode --- __init__.py | 4 +- fast64_internal/f3d/f3d_bleed.py | 2 +- fast64_internal/f3d/f3d_enums.py | 2 +- fast64_internal/f3d/f3d_gbi.py | 66 +++++++++++------------ fast64_internal/f3d/f3d_material.py | 28 +++++----- fast64_internal/f3d/f3d_parser.py | 10 ++-- fast64_internal/f3d/f3d_texture_writer.py | 22 ++++---- fast64_internal/f3d/f3d_writer.py | 8 +-- 8 files changed, 71 insertions(+), 71 deletions(-) diff --git a/__init__.py b/__init__.py index 82f81dc6d..bf8560b56 100644 --- a/__init__.py +++ b/__init__.py @@ -89,7 +89,7 @@ def draw(self, context): col = self.layout.column() col.scale_y = 1.1 # extra padding prop_split(col, context.scene, "f3d_type", "F3D Microcode") - if context.scene.f3d_type == "F3DZEX (AC)": + if context.scene.f3d_type == "F3DZEX2 (Emu64)": prop_split(col, context.scene.fast64.settings, "ac_tri_type", "Triangle Export Type") col.prop(context.scene, "saveTextures") col.prop(context.scene, "f3d_simple", text="Simple Material UI") @@ -100,7 +100,7 @@ def draw(self, context): "While inlining, all meshes will be restored to world default values.\n You can configure these values in the world properties tab.", icon="INFO", ) - if context.scene.f3d_type == "F3DZEX (AC)": + if context.scene.f3d_type == "F3DZEX2 (Emu64)": col.box().label(text="Emu64 supports ignore texture restrictions!", icon="INFO") col.prop(context.scene, "ignoreTextureRestrictions") if context.scene.ignoreTextureRestrictions: diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 88a67ba62..f8753368a 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -105,7 +105,7 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ place_in_flaglist(defaults.g_clipping, "G_CLIPPING", setGeo, clearGeo) if self.f3d.POINT_LIT_GBI: place_in_flaglist(defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", setGeo, clearGeo) - if self.f3d.F3DZEX_AC_EXT: + if self.f3d.F3DZEX2_EMU64: place_in_flaglist(defaults.g_decal_gequal, "G_DECAL_GEQUAL", setGeo, clearGeo) place_in_flaglist(defaults.g_decal_equal, "G_DECAL_EQUAL", setGeo, clearGeo) place_in_flaglist(defaults.g_decal_special, "G_DECAL_SPECIAL", setGeo, clearGeo) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index afa1d06ff..8b29df608 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -395,7 +395,7 @@ "Variant of F3DEX2 family with support for point lighting used in a few games including MM", ), ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen"), - ("F3DZEX (AC)", "F3DZEX (AC)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX"), + ("F3DZEX2 (Emu64)", "F3DZEX2 (Emu64)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX"), ] enumLargeEdges = [ diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 629e89fdb..005626ed0 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -69,7 +69,7 @@ class GfxMatWriteMethod(enum.Enum): "F3DLP.Rej": (80, 32), "F3DEX2/LX2": (32, 32), "F3DEX2/LX2 (Point Lit)": (32, 32), - "F3DZEX (AC)": (2**7, 32), + "F3DZEX2 (Emu64)": (2**7, 32), "F3DEX2.Rej/LX2.Rej": (64, 64), "F3DEX3": (56, 56), } @@ -128,7 +128,7 @@ def isUcodeF3DEX1(F3D_VER: str) -> bool: def isUcodeF3DEX2(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DEX2/LX2 (Point Lit)", "F3DZEX (AC)"} + return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DEX2/LX2 (Point Lit)", "F3DZEX2 (Emu64)"} def isUcodeF3DEX3(F3D_VER: str) -> bool: @@ -136,7 +136,7 @@ def isUcodeF3DEX3(F3D_VER: str) -> bool: def is_ucode_point_lit(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX3", "F3DZEX (AC)", "F3DEX2/LX2 (Point Lit)"} + return F3D_VER in {"F3DEX3", "F3DZEX2 (Emu64)", "F3DEX2/LX2 (Point Lit)"} class F3D: @@ -149,7 +149,7 @@ def __init__(self, F3D_VER): F3DEX_GBI_3 = self.F3DEX_GBI_3 = isUcodeF3DEX3(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) - F3DZEX_AC_EXT = self.F3DZEX_AC_EXT = F3D_VER == "F3DZEX (AC)" + F3DZEX2_EMU64 = self.F3DZEX2_EMU64 = F3D_VER == "F3DZEX2 (Emu64)" POINT_LIT_GBI = self.POINT_LIT_GBI = is_ucode_point_lit(F3D_VER) # F3DEX2 is F3DEX1 and F3DEX3 is F3DEX2, but F3DEX3 is not F3DEX1 @@ -194,7 +194,7 @@ def __init__(self, F3D_VER): self.G_TRIFAN = 0x09 self.G_LIGHTTORDP = 0x0A else: - if F3DZEX_AC_EXT: + if F3DZEX2_EMU64: self.G_TRIN = 0x09 self.G_TRIN_INDEPEND = 0x0A self.G_SETTEXEDGEALPHA = 0xCE @@ -350,7 +350,7 @@ def __init__(self, F3D_VER): self.G_LOD = 0x00100000 # NOT IMPLEMENTED if F3DEX_GBI or F3DLP_GBI: self.G_CLIPPING = 0x00800000 - if F3DZEX_AC_EXT: + if F3DZEX2_EMU64: self.G_DECAL_LEQUAL = 0x00000000 self.G_DECAL_GEQUAL = 0x00000010 self.G_DECAL_EQUAL = 0x00000020 @@ -414,7 +414,7 @@ def __init__(self, F3D_VER): "G_FRESNEL_COLOR", "G_FRESNEL_ALPHA", } - elif F3DZEX_AC_EXT: + elif F3DZEX2_EMU64: self.allGeomModeFlags |= { "G_DECAL_LEQUAL", "G_DECAL_GEQUAL", @@ -3321,10 +3321,10 @@ def to_c_helper(self, texData, bitsPerValue, f3d): code = CData() code.header = f"extern u{str(bitsPerValue)} {self.name}[];\n" - if bitsPerValue != 64 and not f3d.F3DZEX_AC_EXT: # This is to force 8 byte alignment + if bitsPerValue != 64 and not f3d.F3DZEX2_EMU64: # This is to force 8 byte alignment code.source = f"Gfx {self.name}_aligner[] = {{gsSPEndDisplayList()}};\n" code.source += f"u{str(bitsPerValue)} {self.name}[] " - if f3d.F3DZEX_AC_EXT: # Emu64 requires 32 BYTE alignments + if f3d.F3DZEX2_EMU64: # Emu64 requires 32 BYTE alignments code.source += "__attribute__((aligned(32))) " code.source += "= {\n\t" code.source += texData @@ -3764,7 +3764,7 @@ class SPNTrianglesInit_5b(GbiMacro): v8: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( _SHIFTL(f3d.G_TRIN_INDEPEND, 24, 8) | _SHIFTL(self.n - 1, 17, 7) @@ -3775,7 +3775,7 @@ def to_binary(self, f3d, segments): | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), ) else: - raise PluginError("SPNTrianglesInit_5b only available in F3DZEX (AC).") + raise PluginError("SPNTrianglesInit_5b only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -3796,7 +3796,7 @@ class SPNTriangles_5b(GbiMacro): v11: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( _SHIFTL(gsSPNTriangleData1(self.v9, self.v10, self.v11, f3d), 17, 15) | _SHIFTL(gsSPNTriangleData1(self.v6, self.v7, self.v8, f3d), 2, 15) @@ -3806,7 +3806,7 @@ def to_binary(self, f3d, segments): | _SHIFTL(f3d.G_VTX_MODE_5bit, 0, 1), ) else: - raise PluginError("SPNTriangles_5b only available in F3DZEX (AC).") + raise PluginError("SPNTriangles_5b only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -3823,7 +3823,7 @@ class SPNTrianglesInit_7b(GbiMacro): v5: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( _SHIFTL(gsSPNTriangles(self.n, f3d), 0, 32), ( @@ -3833,7 +3833,7 @@ def to_binary(self, f3d, segments): ), ) else: - raise PluginError("SPNTrianglesInit_7b only available in F3DZEX (AC).") + raise PluginError("SPNTrianglesInit_7b only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -3851,7 +3851,7 @@ class SPNTriangles_7b(GbiMacro): v8: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( ( _SHIFTL(gsSPNTriangleData2(self.v6, self.v7, self.v8, f3d), 11, 21) @@ -3864,7 +3864,7 @@ def to_binary(self, f3d, segments): ), ) else: - raise PluginError("SPNTriangles_7b only available in F3DZEX (AC).") + raise PluginError("SPNTriangles_7b only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -4613,7 +4613,7 @@ class DPSetTextureAdjustMode(GbiMacro): mode: str def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( _SHIFTL(f3d.G_SPECIAL_1, 24, 8) | _SHIFTL(f3d.G_SPECIAL_TA_MODE, 16, 8) @@ -4621,7 +4621,7 @@ def to_binary(self, f3d, segments): 0, ) else: - raise PluginError("DPSetTextureAdjustMode only available in F3DZEX (AC).") + raise PluginError("DPSetTextureAdjustMode only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -4836,7 +4836,7 @@ class DPSetTextureImage_Dolphin(GbiMacro): image: FImage def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: fmt = f3d.G_IM_FMT_VARS[self.fmt] siz = f3d.G_IM_SIZ_VARS[self.siz] image_ptr = int.from_bytes(encodeSegmentedAddr(self.image.startAddress, segments), "big") @@ -4850,7 +4850,7 @@ def to_binary(self, f3d, segments): image_ptr, ) else: - raise PluginError("DPSetTextureImage_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPSetTextureImage_Dolphin only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -5046,10 +5046,10 @@ class DPSetTexEdgeAlpha(GbiMacro): alpha: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = (_SHIFTL(f3d.G_SETTEXEDGEALPHA, 24, 8), _SHIFTL(self.alpha, 0, 8)) else: - raise PluginError("DPSetTexEdgeAlpha only available in F3DZEX (AC).") + raise PluginError("DPSetTexEdgeAlpha only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -5094,7 +5094,7 @@ class DPSetTileSize_Dolphin(GbiMacro): height: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( (_SHIFTL(f3d.G_SETTILESIZE, 24, 8) | _SHIFTL(self.s, 10, 14) | _SHIFTL(self.width - 1, 0, 10)), ( @@ -5105,7 +5105,7 @@ def to_binary(self, f3d, segments): ), ) else: - raise PluginError("DPSetTileSize_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPSetTileSize_Dolphin only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -5173,7 +5173,7 @@ class DPSetTile_Dolphin(GbiMacro): shift_t: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: assert self.d_fmt == f3d.G_DOLPHIN_TLUT_DEFAULT_MODE words = ( ( @@ -5189,7 +5189,7 @@ def to_binary(self, f3d, segments): 0, ) else: - raise PluginError("DPSetTile_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPSetTile_Dolphin only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") @@ -5528,7 +5528,7 @@ class DPLoadTextureBlock_4b_Dolphin(GbiMacro): st: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.timg).to_binary( f3d, segments ) + DPSetTile_Dolphin( @@ -5537,7 +5537,7 @@ def to_binary(self, f3d, segments): f3d, segments ) else: - raise PluginError("DPLoadTextureBlock_4b_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPLoadTextureBlock_4b_Dolphin only available in F3DZEX2 (Emu64).") def size(self, f3d): return GFX_SIZE * 2 @@ -5706,12 +5706,12 @@ class DPLoadTextureTile_4b_Dolphin(GbiMacro): height: int def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: return DPSetTextureImage_Dolphin(self.fmt, f3d.G_IM_SIZ_4b, self.height, self.width, self.img).to_binary( f3d, segments ) + DPSetTile_Dolphin("G_DOLPHIN_TLUT_DEFAULT_MODE", 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) else: - raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPLoadTextureTile_4b_Dolphin only available in F3DZEX2 (Emu64).") def size(self, f3d): return GFX_SIZE * 2 @@ -5790,7 +5790,7 @@ class DPLoadTLUT_Dolphin(GbiMacro): addr: FImage def to_binary(self, f3d, segments): - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: words = ( _SHIFTL(f3d.G_LOADTLUT, 24, 8) | _SHIFTL(f3d.G_TLUT_DOLPHIN, 22, 2) @@ -5800,7 +5800,7 @@ def to_binary(self, f3d, segments): self.addr, ) else: - raise PluginError("DPLoadTLUT_Dolphin only available in F3DZEX (AC).") + raise PluginError("DPLoadTLUT_Dolphin only available in F3DZEX2 (Emu64).") return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 51e2b9c73..7ea0f3bd6 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -504,7 +504,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], elif blendWarnings and not shadeInBlender and settings.g_fog: c.label(text="Fog not used in rendermode / blender, can disable.", icon="INFO") - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: c = indentGroup(inputGroup, "Decals:", True) c.prop(settings, "g_decal_equal") c.prop(settings, "g_decal_gequal") @@ -652,7 +652,7 @@ def ui_other(settings, dataHolder, layout, useDropdown): prop_input.prop(dataHolder, "blend_color", text="") prop_input.enabled = dataHolder.set_blend - if bpy.context.scene.f3d_type == "F3DZEX (AC)": + if bpy.context.scene.f3d_type == "F3DZEX2 (Emu64)": inputGroup.separator() adjust_row = inputGroup.row() adjust_row.prop(dataHolder, "set_bilerp_text_adjust", text="Bilerp Adjust Mode") @@ -1734,7 +1734,7 @@ def set_output_node_groups(material: Material): output_node.inputs["Cycle_A_2"].default_value = 0.5 if output_method == "CLIP": output_node.inputs["Alpha Threshold"].default_value = 0.125 - if bpy.context.scene.f3d_type == "F3DZEX (AC)" and f3dMat.rdp_settings.is_emu64_texedge: + if bpy.context.scene.f3d_type == "F3DZEX2 (Emu64)" and f3dMat.rdp_settings.is_emu64_texedge: output_node.inputs["Alpha Threshold"].default_value = f3dMat.tex_edge_alpha material.node_tree.links.new(nodes["Cycle_1"].outputs["Color"], output_node.inputs["Cycle_C_1"]) material.node_tree.links.new(nodes["Cycle_1"].outputs["Alpha"], output_node.inputs["Cycle_A_1"]) @@ -2856,12 +2856,12 @@ class TextureProperty(PropertyGroup): default=16, ) use_pal_index: bpy.props.BoolProperty( - name="Palette Index Reference", description="F3DZEX (AC): Reference an already loaded palette" + name="Palette Index Reference", description="F3DZEX2 (Emu64): Reference an already loaded palette" ) pal_index: bpy.props.StringProperty( name="Palette Index", default="0x03", - description="F3DZEX (AC): The palette's index. Defaults to the grass pallete index (3)", + description="F3DZEX2 (Emu64): The palette's index. Defaults to the grass pallete index (3)", ) menu: bpy.props.BoolProperty() @@ -2940,7 +2940,7 @@ def ui_image( name: str, showCheckBox: bool, ): - is_fdzex_ac = bpy.context.scene.f3d_type == "F3DZEX (AC)" + is_fdzex_ac = bpy.context.scene.f3d_type == "F3DZEX2 (Emu64)" inputGroup = layout.box().column() inputGroup.prop( @@ -3010,7 +3010,7 @@ def ui_image( if textureProp.tex_format[:2] == "CI": prop_split(prop_input, textureProp, "ci_format", name="CI Format") if is_fdzex_ac and textureProp.ci_format == "IA16": - multilineLabel(prop_input, text="IA16 not supported in F3DZEX (AC).", icon="ERROR") + multilineLabel(prop_input, text="IA16 not supported in F3DZEX2 (Emu64).", icon="ERROR") if not isLarge: s, t = textureProp.S, textureProp.T if width > 0 and height > 0: @@ -3037,7 +3037,7 @@ def ui_image( if is_fdzex_ac and ((s.clamp and s.mirror) or (t.clamp and t.mirror)): texFieldSettings.box().label( - text="Clamp + mirror not supported in F3DZEX (AC).", + text="Clamp + mirror not supported in F3DZEX2 (Emu64).", icon="ERROR", ) @@ -3260,13 +3260,13 @@ class RDPSettings(PropertyGroup): name="Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Disables any offset and uses the equal compare mode", + description="F3DZEX2 (Emu64): Disables any offset and uses the equal compare mode", ) g_decal_gequal: bpy.props.BoolProperty( name="Greater or Equal", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): When enabled, the greater or equal compare mode is used, " + description="F3DZEX2 (Emu64): When enabled, the greater or equal compare mode is used, " "if Equal is disabled a positive offset is also used (closer to the camera).\n" "When disabled, the default negative offset and less or equal compare mode are used", ) @@ -3274,7 +3274,7 @@ class RDPSettings(PropertyGroup): name="Special", default=False, update=update_node_values_with_preset, - description="F3DZEX (AC): Apropriately sets decal blend modes", + description="F3DZEX2 (Emu64): Apropriately sets decal blend modes", ) # v1/2 difference g_cull_front: bpy.props.BoolProperty( @@ -3695,7 +3695,7 @@ def geo_mode_to_dict(self, f3d=None): data.update(self.attributes_to_dict(self.geo_mode_f3dex_attributes)) if f3d.F3DEX_GBI_3: data.update(self.attributes_to_dict(self.geo_mode_f3dex3_attributes)) - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: data.update(self.attributes_to_dict(self.geo_mode_f3dzex_ac_attributes)) return data @@ -4420,14 +4420,14 @@ class F3DMaterialProperty(PropertyGroup): step=100.0 / 255.0, default=144.0 / 255.0, update=update_node_values_with_preset, - description="F3DZEX (AC): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal", + description="F3DZEX2 (Emu64): Alpha threshold for tex edge (cutout) materials, displays only alpha values greater or equal", ) bilerp_text_adjust: bpy.props.EnumProperty( name="Bilerp Adjust Mode", items=enumTextAdjust, default="G_TA_N64", update=update_node_values_without_preset, - description="F3DZEX (AC): Changes bilerp filter origin", + description="F3DZEX2 (Emu64): Changes bilerp filter origin", ) prim_color: bpy.props.FloatVectorProperty( name="Primitive Color", diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 2f7015d37..016f8c3eb 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -530,7 +530,7 @@ def initContext(self): self.numLights: int = 0 self.lightData: dict[Light, bpy.types.Object] = {} # Light : blender light object - self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + self.ac_pal_dict: dict[int, int] = {} # F3DZEX2 (Emu64) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) self.tri_init_count = 0 @@ -599,7 +599,7 @@ def clearMaterial(self): self.lights.a = Ambient([0, 0, 0]) self.numLights = 0 - self.ac_pal_dict: dict[int, int] = {} # F3DZEX (AC) + self.ac_pal_dict: dict[int, int] = {} # F3DZEX2 (Emu64) self.set_img = DPSetTextureImage_Dolphin("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 0, 0, None) self.tri_init_count = 0 @@ -785,7 +785,7 @@ def applyTLUTToIndex(self, index): if texProp.tex_format[:2] == "CI": # Only handles TLUT at 256 - if self.f3d.F3DZEX_AC_EXT: + if self.f3d.F3DZEX2_EMU64: tlutName = self.ac_pal_dict.get(self.getTileSettings(index).palette, None) else: tlutName = self.tmemDict.get(256, None) @@ -900,7 +900,7 @@ def setGeoFlags(self, command: "ParsedMacro", value: bool): rdp_settings.g_fresnel_color = value if bitFlags & self.f3d.G_FRESNEL_ALPHA: rdp_settings.g_fresnel_alpha = value - elif self.f3d.F3DZEX_AC_EXT: + elif self.f3d.F3DZEX2_EMU64: if bitFlags & self.f3d.G_DECAL_GEQUAL: rdp_settings.g_decal_gequal = value if bitFlags & self.f3d.G_DECAL_EQUAL: @@ -954,7 +954,7 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_lighting_specular = False rdp_settings.g_fresnel_color = False rdp_settings.g_fresnel_alpha = False - if self.f3d.F3DZEX_AC_EXT: + if self.f3d.F3DZEX2_EMU64: rdp_settings.g_decal_gequal = bitFlags & self.f3d.G_DECAL_GEQUAL != 0 rdp_settings.g_decal_equal = bitFlags & self.f3d.G_DECAL_EQUAL != 0 rdp_settings.g_decal_special = bitFlags & self.f3d.G_DECAL_SPECIAL != 0 diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index eea246479..9b80aa0dd 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -206,7 +206,7 @@ def maybeSaveSingleLargeTextureSetup( sm = 2 if is4bit else 4 nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] if curImgSet != i: - if fModel.f3d.F3DZEX_AC_EXT: + if fModel.f3d.F3DZEX2_EMU64: gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, texDimensions[1], wid, fImage)) else: gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) @@ -480,7 +480,7 @@ def moreSetupFromModel( fMaterial, material, self.indexInMat ) if self.isTexRef: - if fModel.f3d.F3DZEX_AC_EXT and self.texProp.use_pal_index: + if fModel.f3d.F3DZEX2_EMU64 and self.texProp.use_pal_index: self.palLen = 16 if self.texFormat == "CI4" else 256 self.palIndex = int(self.texProp.pal_index, 0) elif self.flipbook is not None: @@ -489,7 +489,7 @@ def moreSetupFromModel( self.palLen = self.texProp.pal_reference_size else: assert self.flipbook is None - self.pal = getColorsUsedInImage(self.texProp.tex, self.palFormat, fModel.f3d.F3DZEX_AC_EXT) + self.pal = getColorsUsedInImage(self.texProp.tex, self.palFormat, fModel.f3d.F3DZEX2_EMU64) self.palLen = len(self.pal) if self.palLen > (16 if self.texFormat == "CI4" else 256): raise PluginError( @@ -560,7 +560,7 @@ def writeAll( else: if self.isTexCI: writeCITextureData( - self.texProp.tex, fImage, self.pal, self.palFormat, self.texFormat, f3d.F3DZEX_AC_EXT + self.texProp.tex, fImage, self.pal, self.palFormat, self.texFormat, f3d.F3DZEX2_EMU64 ) else: writeNonCITextureData(self.texProp.tex, fImage, self.texFormat) @@ -629,7 +629,7 @@ def writeAll( # Determine how to arrange / load palette entries into upper half of tmem if self.isCI: assert self.ti0.useTex or self.ti1.useTex - if fModel.f3d.F3DZEX_AC_EXT: + if fModel.f3d.F3DZEX2_EMU64: non_rgba = False if self.ti0.useTex: if self.ti0.pal: @@ -645,7 +645,7 @@ def writeAll( non_rgba = self.ti1.palFormat != "RGBA16" if non_rgba: raise PluginError( - f"In material {material.name}: Only RGBA16 palette format supported in F3DZEX (AC)" + f"In material {material.name}: Only RGBA16 palette format supported in F3DZEX2 (Emu64)" ) elif not self.ti1.useTex: self.ti0.loadPal = True @@ -978,7 +978,7 @@ def saveTextureLoadOnly( # LoadTile will pad rows to 64 bit word alignment, while # LoadBlock assumes this is already done. - needs_load = not f3d.F3DZEX_AC_EXT + needs_load = not f3d.F3DZEX2_EMU64 useLoadBlock = canUseLoadBlock(fImage, texProp.tex_format, f3d) and needs_load line = 0 if useLoadBlock else getTileLine(fImage, SL, SH, siz, f3d) wid = 1 if useLoadBlock else fImage.width @@ -1009,7 +1009,7 @@ def saveTextureLoadOnly( loadCommand = DPLoadTile(loadtile, sl, tl, sh, th) if not omitSetTextureImage: - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: gfxOut.commands.append(DPSetTextureImage_Dolphin(fmt, siz, height, wid, fImage)) else: gfxOut.commands.append(DPSetTextureImage(fmt, siz, wid, fImage)) @@ -1060,9 +1060,9 @@ def saveTextureTile( SL, _, SH, _, sl, tl, sh, th = getTileSizeSettings(texProp, tileSettings, f3d) line = getTileLine(fImage, SL, SH, siz, f3d) - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: if (clamp_S and mirror_S) or (clamp_T and mirror_T): - raise PluginError("Clamp + mirror not supported in F3DZEX (AC)") + raise PluginError("Clamp + mirror not supported in F3DZEX2 (Emu64)") if tileSettings and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): raise PluginError("Mask is not emulated in emu64, non default values are not supported") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" @@ -1102,7 +1102,7 @@ def savePaletteLoad( assert 0 <= palAddr < 256 and (palAddr & 0xF) == 0 palFmt = texFormatOf[palFormat] nocm = ["G_TX_WRAP", "G_TX_NOMIRROR"] - if f3d.F3DZEX_AC_EXT: + if f3d.F3DZEX2_EMU64: assert palFormat == "RGBA16" gfxOut.commands.append(DPLoadTLUT_Dolphin(palIndex, palLen - 1, 1, fPalette)) return diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index b0ba674fc..62ce9c78f 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1125,7 +1125,7 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional self.triList.commands.append(SPAlphaCompareCull("G_ALPHA_COMPARE_CULL_DISABLE", 0)) def get_best_load_size_and_tri_type(self, vertices_up_next: int): - if self.triConverterInfo.f3d.F3DZEX_AC_EXT: + if self.triConverterInfo.f3d.F3DZEX2_EMU64: setting = bpy.context.scene.fast64.settings.ac_tri_type if (setting == "Auto" and vertices_up_next > 2**5) or setting == "7b": return True, 2**7 @@ -1245,7 +1245,7 @@ def createTriangleCommands(triangles, vertexBuffer, ac_use_7b, triConverterInfo) def getIndices(*tris): return [vertexBuffer.index(v) for tri in tris for v in tri] - if triConverterInfo.f3d.F3DZEX_AC_EXT: + if triConverterInfo.f3d.F3DZEX2_EMU64: def get_n_tris_indices(n: int, tri_index=0, triangles=triangles): # Includes dummy data to fill out the command if len(triangles) - tri_index >= n: @@ -1655,7 +1655,7 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_lighting_specular, defaults.g_lighting_specular, "G_LIGHTING_SPECULAR", *args) saveFunc(settings.g_fresnel_color, defaults.g_fresnel_color, "G_FRESNEL_COLOR", *args) saveFunc(settings.g_fresnel_alpha, defaults.g_fresnel_alpha, "G_FRESNEL_ALPHA", *args) - elif f3d.F3DZEX_AC_EXT: + elif f3d.F3DZEX2_EMU64: saveFunc(settings.g_decal_gequal, defaults.g_decal_gequal, "G_DECAL_GEQUAL", *args) saveFunc(settings.g_decal_equal, defaults.g_decal_equal, "G_DECAL_EQUAL", *args) saveFunc(settings.g_decal_special, defaults.g_decal_special, "G_DECAL_SPECIAL", *args) @@ -1881,7 +1881,7 @@ def saveOtherDefinition(fMaterial, material, defaults): int(material.blend_color[3] * 255), ) ) - if bpy.context.scene.f3d_type == "F3DZEX (AC)": + if bpy.context.scene.f3d_type == "F3DZEX2 (Emu64)": if material.set_tex_edge_alpha: fMaterial.mat_only_DL.commands.append(DPSetTexEdgeAlpha(int(material.tex_edge_alpha * 255))) if material.set_bilerp_text_adjust: From 8828b38b820eb149561f046e4645789279deb5a1 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 7 Aug 2024 13:21:47 +0100 Subject: [PATCH 77/82] Add fixed index for the ucode enum --- fast64_internal/f3d/f3d_enums.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 8b29df608..3e3bccd76 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -383,19 +383,25 @@ } enumF3D = [ - ("F3D", "F3D", "Original microcode used in SM64"), - ("F3DEX/LX", "F3DEX/LX", "F3DEX version 1"), - ("F3DLX.Rej", "F3DLX.Rej", "F3DLX.Rej"), - ("F3DLP.Rej", "F3DLP.Rej", "F3DLP.Rej"), - ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT"), - ("F3DEX2.Rej/LX2.Rej", "F3DEX2.Rej/LX2.Rej", "Variant of F3DEX2 family using vertex rejection instead of clipping"), + ("F3D", "F3D", "Original microcode used in SM64", 0), + ("F3DEX/LX", "F3DEX/LX", "F3DEX version 1", 1), + ("F3DLX.Rej", "F3DLX.Rej", "F3DLX.Rej", 2), + ("F3DLP.Rej", "F3DLP.Rej", "F3DLP.Rej", 3), + ("F3DEX2/LX2", "F3DEX2/LX2/ZEX", "Family of microcodes used in later N64 games including OoT", 4), + ( + "F3DEX2.Rej/LX2.Rej", + "F3DEX2.Rej/LX2.Rej", + "Variant of F3DEX2 family using vertex rejection instead of clipping", + 5, + ), ( "F3DEX2/LX2 (Point Lit)", "F3DEX2/LX2 (Point Lit)", "Variant of F3DEX2 family with support for point lighting used in a few games including MM", + 7, ), - ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen"), - ("F3DZEX2 (Emu64)", "F3DZEX2 (Emu64)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX"), + ("F3DEX3", "F3DEX3", "Custom microcode by Sauraen", 6), + ("F3DZEX2 (Emu64)", "F3DZEX2 (Emu64)", "Microcode used in Animal Crossing (GC), extended version of F3DZEX", 8), ] enumLargeEdges = [ From d6c02b4011711bb3ecb012a11454d95bfa9be069 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 18 Aug 2024 13:55:57 +0100 Subject: [PATCH 78/82] Use removeComments --- fast64_internal/f3d/f3d_parser.py | 2 +- fast64_internal/utility.py | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 016f8c3eb..014f494b3 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -2389,7 +2389,7 @@ def importMeshC( f3dContext.mat().draw_layer.oot = drawLayer transformMatrix = mathutils.Matrix.Scale(1 / scale, 4) - parseF3D(comment_remover(data), name, transformMatrix, name, name, "oot", drawLayer, f3dContext, True) + parseF3D(removeComments(data), name, transformMatrix, name, name, "oot", drawLayer, f3dContext, True) f3dContext.createMesh(obj, removeDoubles, importNormals, callClearMaterial) applyRotation([obj], math.radians(-90), "X") diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index d184be045..ac96799c7 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1876,16 +1876,3 @@ def upgrade_old_prop( print(f"Failed to upgrade {new_prop} from old location {old_loc} with props {old_props}") traceback.print_exc() return False - - -def comment_remover(text): - # https://stackoverflow.com/a/241506 - def replacer(match): - s = match.group(0) - if s.startswith("/"): - return " " # note: a space and not an empty string - else: - return s - - pattern = re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE) - return re.sub(pattern, replacer, text) From 2029002b44cd271e0ee1d31c9cc9c0b48b778231 Mon Sep 17 00:00:00 2001 From: Lila Date: Sun, 15 Sep 2024 12:11:09 +0100 Subject: [PATCH 79/82] [F3D] Backport point lit ucode from AC pr --- __init__.py | 4 +- fast64_internal/f3d/f3d_bleed.py | 2 +- fast64_internal/f3d/f3d_enums.py | 4 +- fast64_internal/f3d/f3d_gbi.py | 8 ++-- fast64_internal/f3d/f3d_material.py | 23 ++++++--- fast64_internal/f3d/f3d_material_presets.py | 52 +++++++++++++++++++++ fast64_internal/f3d/f3d_parser.py | 1 - fast64_internal/oot/oot_constants.py | 1 + fast64_internal/sm64/sm64_constants.py | 1 + 9 files changed, 80 insertions(+), 16 deletions(-) diff --git a/__init__.py b/__init__.py index 5a22af3f3..67e66a455 100644 --- a/__init__.py +++ b/__init__.py @@ -338,9 +338,9 @@ def upgrade_changed_props(): OOT_ObjectProperties.upgrade_changed_props() for scene in bpy.data.scenes: settings: Fast64Settings_Properties = scene.fast64.settings - if settings.internal_game_update_ver != 1: + if settings.internal_game_update_ver < 2: set_game_defaults(scene, False) - settings.internal_game_update_ver = 1 + settings.internal_game_update_ver = 2 if scene.get("decomp_compatible", False): scene.gameEditorMode = "Homebrew" del scene["decomp_compatible"] diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 4d857fd06..001b917d9 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -102,7 +102,7 @@ def place_in_flaglist(flag: bool, enum: str, set_list: SPSetGeometryMode, clear_ place_in_flaglist(defaults.g_tex_gen, "G_TEXTURE_GEN", setGeo, clearGeo) place_in_flaglist(defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", setGeo, clearGeo) place_in_flaglist(defaults.g_shade_smooth, "G_SHADING_SMOOTH", setGeo, clearGeo) - if self.f3d.F3D_OLD_GBI: + if self.f3d.F3DEX_GBI: place_in_flaglist(defaults.g_clipping, "G_CLIPPING", setGeo, clearGeo) if self.f3d.POINT_LIT_GBI: place_in_flaglist(defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", setGeo, clearGeo) diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index 3e3bccd76..8b2394868 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -395,8 +395,8 @@ 5, ), ( - "F3DEX2/LX2 (Point Lit)", - "F3DEX2/LX2 (Point Lit)", + "F3DEX2_PL", + "F3DEX2 (Point Lit)", "Variant of F3DEX2 family with support for point lighting used in a few games including MM", 7, ), diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 300a01121..0b12846a5 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -68,10 +68,10 @@ class GfxMatWriteMethod(enum.Enum): "F3DLX.Rej": (64, 32), "F3DLP.Rej": (80, 32), "F3DEX2/LX2": (32, 32), - "F3DEX2/LX2 (Point Lit)": (32, 32), - "F3DZEX2 (Emu64)": (2**7, 32), + "F3DEX2_PL": (32, 32), "F3DEX2.Rej/LX2.Rej": (64, 64), "F3DEX3": (56, 56), + "F3DZEX2 (Emu64)": (2**7, 32), } sm64_default_draw_layers = { @@ -139,7 +139,7 @@ def isUcodeF3DEX1(F3D_VER: str) -> bool: def isUcodeF3DEX2(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DEX2/LX2 (Point Lit)", "F3DZEX2 (Emu64)"} + return F3D_VER in {"F3DEX2.Rej/LX2.Rej", "F3DEX2/LX2", "F3DEX2_PL", "F3DZEX2 (Emu64)"} def isUcodeF3DEX3(F3D_VER: str) -> bool: @@ -147,7 +147,7 @@ def isUcodeF3DEX3(F3D_VER: str) -> bool: def is_ucode_point_lit(F3D_VER: str) -> bool: - return F3D_VER in {"F3DEX3", "F3DZEX2 (Emu64)", "F3DEX2/LX2 (Point Lit)"} + return F3D_VER in {"F3DEX3", "F3DEX2_PL", "F3DZEX2 (Emu64)"} class F3D: diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 9a4c8ead0..d2b23984c 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -573,7 +573,8 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if blendWarnings and settings.zmode != "ZMODE_DEC": decal_mode_info = "Non-decal rendermode, these will be ignored." multilineLabel(c, decal_mode_info, icon="INFO") - elif f3d.F3DEX_GBI_3: + + if f3d.F3DEX_GBI_3: c = indentGroup(inputGroup, "Attribute offsets:", True) c.prop(settings, "g_attroffset_st_enable") c.prop(settings, "g_attroffset_z_enable") @@ -607,8 +608,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], if f3d.F3DEX_GBI: c.prop(settings, "g_clipping") elif f3d.F3DEX_GBI_3: - c.prop(settings, "g_lighting_positional") - c.label(text="Always enabled in F3DEX3", icon="INFO") + c.prop(settings, "g_lighting_positional", text="Positional Lighting (Always enabled in EX3)") def ui_upper_mode(settings, dataHolder, layout: UILayout, useDropdown): @@ -3414,9 +3414,9 @@ class RDPSettings(PropertyGroup): ) g_lighting_positional: bpy.props.BoolProperty( name="Positional Lighting", - default=True, + default=False, update=update_node_values_with_preset, - description="F3DEX/ZEX: Enables calculating shade color using positional lights along with directional, ignored in F3DEX3", + description="F3DEX2 (Point Lit): Enables calculating shade color using positional lights along with directional, ignored in F3DEX3", ) # upper half mode @@ -3718,6 +3718,10 @@ def attributes_from_dict(self, data: dict, info: dict): ("clipping", "g_clipping", True), ] + geo_mode_pl_attributes = [ + ("positionalLighting", "g_lighting_positional", False), + ] + geo_mode_f3dex3_attributes = [ ("ambientOcclusion", "g_ambocclusion", False), ("attroffsetZ", "g_attroffset_z_enable", False), @@ -3734,8 +3738,13 @@ def attributes_from_dict(self, data: dict, info: dict): ("decalEqual", "g_decal_equal", False), ("decalSpecial", "g_decal_special", False), ] + geo_mode_attributes = ( - geo_mode_all_attributes + geo_mode_f3dex_attributes + geo_mode_f3dex3_attributes + geo_mode_f3dzex_ac_attributes + geo_mode_all_attributes + + geo_mode_f3dex_attributes + + geo_mode_pl_attributes + + geo_mode_f3dex3_attributes + + geo_mode_f3dzex_ac_attributes ) def geo_mode_to_dict(self, f3d=None): @@ -3743,6 +3752,8 @@ def geo_mode_to_dict(self, f3d=None): data = self.attributes_to_dict(self.geo_mode_all_attributes) if f3d.F3DEX_GBI or f3d.F3DLP_GBI: data.update(self.attributes_to_dict(self.geo_mode_f3dex_attributes)) + if f3d.POINT_LIT_GBI: + data.update(self.attributes_to_dict(self.geo_mode_pl_attributes)) if f3d.F3DEX_GBI_3: data.update(self.attributes_to_dict(self.geo_mode_f3dex3_attributes)) if f3d.F3DZEX2_EMU64: diff --git a/fast64_internal/f3d/f3d_material_presets.py b/fast64_internal/f3d/f3d_material_presets.py index 2a9c26a2b..974d184e5 100644 --- a/fast64_internal/f3d/f3d_material_presets.py +++ b/fast64_internal/f3d/f3d_material_presets.py @@ -88,6 +88,7 @@ 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_lighting_positional = True 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' @@ -201,6 +202,7 @@ 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_lighting_positional = True 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' @@ -314,6 +316,7 @@ 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_lighting_positional = True 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' @@ -427,6 +430,7 @@ 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_lighting_positional = True 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' @@ -540,6 +544,7 @@ 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_lighting_positional = True 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' @@ -653,6 +658,7 @@ 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_lighting_positional = True 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' @@ -766,6 +772,7 @@ 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_lighting_positional = True 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' @@ -879,6 +886,7 @@ 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_lighting_positional = True 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' @@ -992,6 +1000,7 @@ 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_lighting_positional = True 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' @@ -1105,6 +1114,7 @@ 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_lighting_positional = True 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' @@ -1218,6 +1228,7 @@ 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_lighting_positional = True 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' @@ -1331,6 +1342,7 @@ 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_lighting_positional = True 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' @@ -1444,6 +1456,7 @@ 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_lighting_positional = True 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' @@ -1557,6 +1570,7 @@ 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_lighting_positional = True 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' @@ -1670,6 +1684,7 @@ 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_lighting_positional = True 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' @@ -1783,6 +1798,7 @@ 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_lighting_positional = True 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' @@ -1895,6 +1911,7 @@ 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_lighting_positional = True 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' @@ -2007,6 +2024,7 @@ 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_lighting_positional = True 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' @@ -2119,6 +2137,7 @@ 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_lighting_positional = True 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' @@ -2231,6 +2250,7 @@ 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_lighting_positional = True 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' @@ -2343,6 +2363,7 @@ 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_lighting_positional = True 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' @@ -2455,6 +2476,7 @@ 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_lighting_positional = True 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' @@ -2567,6 +2589,7 @@ 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_lighting_positional = True 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' @@ -2679,6 +2702,7 @@ 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_lighting_positional = True 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' @@ -2791,6 +2815,7 @@ 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_lighting_positional = True 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' @@ -2903,6 +2928,7 @@ 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_lighting_positional = True 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' @@ -3015,6 +3041,7 @@ 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_lighting_positional = True 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' @@ -3127,6 +3154,7 @@ 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_lighting_positional = True 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' @@ -3239,6 +3267,7 @@ 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_lighting_positional = True 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' @@ -3352,6 +3381,7 @@ 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_lighting_positional = True 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' @@ -3466,6 +3496,7 @@ 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_lighting_positional = True 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' @@ -3587,6 +3618,7 @@ 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_lighting_positional = True f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_DISABLE' f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' @@ -3758,6 +3790,7 @@ 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_lighting_positional = True f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_DISABLE' f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' @@ -3909,6 +3942,7 @@ 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_lighting_positional = True f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_DISABLE' f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' @@ -4060,6 +4094,7 @@ 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_lighting_positional = True f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_DISABLE' f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' @@ -4211,6 +4246,7 @@ 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_lighting_positional = True f3d_mat.rdp_settings.g_mdsft_alpha_dither = 'G_AD_DISABLE' f3d_mat.rdp_settings.g_mdsft_rgb_dither = 'G_CD_MAGICSQ' f3d_mat.rdp_settings.g_mdsft_combkey = 'G_CK_NONE' @@ -4362,6 +4398,7 @@ 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_lighting_positional = True 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' @@ -4494,6 +4531,7 @@ 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_lighting_positional = True 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' @@ -4626,6 +4664,7 @@ 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_lighting_positional = True 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' @@ -4758,6 +4797,7 @@ 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_lighting_positional = True 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' @@ -4890,6 +4930,7 @@ 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_lighting_positional = True 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' @@ -5022,6 +5063,7 @@ 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_lighting_positional = True 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' @@ -5154,6 +5196,7 @@ 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_lighting_positional = True 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' @@ -5286,6 +5329,7 @@ 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_lighting_positional = True 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' @@ -5418,6 +5462,7 @@ 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_lighting_positional = True 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' @@ -5550,6 +5595,7 @@ 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_lighting_positional = True 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' @@ -5682,6 +5728,7 @@ 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_lighting_positional = True 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' @@ -5814,6 +5861,7 @@ 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_lighting_positional = True 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' @@ -5946,6 +5994,7 @@ 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_lighting_positional = True 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' @@ -6078,6 +6127,7 @@ 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_lighting_positional = True 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' @@ -6210,6 +6260,7 @@ 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_lighting_positional = True 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' @@ -6342,6 +6393,7 @@ 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_lighting_positional = True 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' diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 04724a135..61b7105ed 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -971,7 +971,6 @@ def loadGeoFlags(self, command: "ParsedMacro"): rdp_settings.g_lighting_positional = bitFlags & self.f3d.G_LIGHTING_POSITIONAL != 0 else: rdp_settings.g_lighting_positional = False - rdp_settings.g_fog = bitFlags & self.f3d.G_FOG != 0 rdp_settings.g_lighting = bitFlags & self.f3d.G_LIGHTING != 0 rdp_settings.g_tex_gen = bitFlags & self.f3d.G_TEXTURE_GEN != 0 diff --git a/fast64_internal/oot/oot_constants.py b/fast64_internal/oot/oot_constants.py index a0b33813c..e2e55f754 100644 --- a/fast64_internal/oot/oot_constants.py +++ b/fast64_internal/oot/oot_constants.py @@ -610,6 +610,7 @@ "cullBack": True, "lighting": True, "shadeSmooth": True, + "positionalLighting": True, }, "otherModeH": { "alphaDither": "G_AD_NOISE", diff --git a/fast64_internal/sm64/sm64_constants.py b/fast64_internal/sm64/sm64_constants.py index fd1893770..b56ae0185 100644 --- a/fast64_internal/sm64/sm64_constants.py +++ b/fast64_internal/sm64/sm64_constants.py @@ -2359,6 +2359,7 @@ def __init__(self, geoAddr, level, switchDict): "cullBack": True, "lighting": True, "shadeSmooth": True, + "positionalLighting": True, }, "otherModeH": { "textureFilter": "G_TF_BILERP", From 24ebe8c6cddb8f295ca72e8e72f012373cdfb442 Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 9 Oct 2024 13:35:38 +0100 Subject: [PATCH 80/82] Noted issue Co-Authored-By: Dragorn421 --- fast64_internal/f3d/f3d_material.py | 2 +- fast64_internal/f3d/f3d_writer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index d2b23984c..4048e382b 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -605,7 +605,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c = indentGroup(inputGroup, "Not useful:", True) c.prop(settings, "g_lod") - if f3d.F3DEX_GBI: + if f3d.F3DLP_GBI: c.prop(settings, "g_clipping") elif f3d.F3DEX_GBI_3: c.prop(settings, "g_lighting_positional", text="Positional Lighting (Always enabled in EX3)") diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 85e40e48a..1a3d82aa3 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -1665,7 +1665,7 @@ def saveGeoModeCommon(saveFunc: Callable, settings: RDPSettings, defaults: RDPSe saveFunc(settings.g_tex_gen_linear, defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", *args) saveFunc(settings.g_lod, defaults.g_lod, "G_LOD", *args) saveFunc(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", *args) - if f3d.F3DEX_GBI: + if f3d.F3DLP_GBI: saveFunc(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", *args) if f3d.POINT_LIT_GBI: saveFunc(settings.g_lighting_positional, defaults.g_lighting_positional, "G_LIGHTING_POSITIONAL", *args) From f24c2544f94f0cdd796ebdb706bf80a347db15be Mon Sep 17 00:00:00 2001 From: Lila Date: Wed, 25 Dec 2024 20:56:39 +0000 Subject: [PATCH 81/82] rewrite textures to use numpy rewrite textures to use numpy implemented gc swizzle after im sure its ready to backport ill make another pr --- fast64_internal/f3d/f3d_gbi.py | 41 +-- fast64_internal/f3d/f3d_texture_writer.py | 337 ++++++++-------------- fast64_internal/utility.py | 7 +- 3 files changed, 142 insertions(+), 243 deletions(-) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 0b12846a5..e69547a12 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -134,6 +134,9 @@ class GfxMatWriteMethod(enum.Enum): } +EMU64_SWIZZLE_SIZES = {"G_IM_SIZ_4b": (8, 8), "G_IM_SIZ_8b": (8, 4), "G_IM_SIZ_16b": (4, 4), "G_IM_SIZ_32b": (2, 2)} + + def isUcodeF3DEX1(F3D_VER: str) -> bool: return F3D_VER in {"F3DLP.Rej", "F3DLX.Rej", "F3DEX/LX"} @@ -3311,16 +3314,16 @@ class FImage: width: int height: int filename: str - data: bytearray = field(init=False, compare=False, default_factory=bytearray) + data: np.ndarray = field(init=False, compare=False, default=np.ndarray([])) startAddress: int = field(init=False, compare=False, default=0) isLargeTexture: bool = field(init=False, compare=False, default=False) converted: bool = field(init=False, compare=False, default=False) def size(self): - return len(self.data) + return self.data.size * self.data.itemsize def to_binary(self): - return self.data + return self.data.astype(self.data.dtype.newbyteorder(">")).tobytes() def to_c(self, texArrayBitSize, f3d): return self.to_c_helper(self.to_c_data(texArrayBitSize), texArrayBitSize, f3d) @@ -3342,38 +3345,14 @@ def to_c_helper(self, texData, bitsPerValue, f3d): code.source += "\n};\n\n" return code - def to_c_data(self, bitsPerValue): + def to_c_data(self, bits_per_val: int): if not self.converted: raise PluginError( "Error: Trying to write texture data to C, but haven't actually converted the image file to bytes yet." ) - - bytesPerValue = int(bitsPerValue / 8) - numValues = int(len(self.data) / bytesPerValue) - remainderCount = len(self.data) - numValues * bytesPerValue - digits = 2 + 2 * bytesPerValue - - code = "".join( - [ - format( - int.from_bytes(self.data[i * bytesPerValue : (i + 1) * bytesPerValue], "big"), - "#0" + str(digits) + "x", - ) - + ", " - + ("\n\t" if i % 8 == 7 else "") - for i in range(numValues) - ] - ) - - if remainderCount > 0: - start = numValues * bytesPerValue - end = (numValues + 1) * bytesPerValue - code += format( - int.from_bytes(self.data[start:end], "big") << (8 * (bytesPerValue - remainderCount)), - "#0" + str(digits) + "x", - ) - - return code + data = self.data.astype(dtype=self.data.dtype.newbyteorder(">")) + hex_str = data.tobytes().hex(":", bits_per_val // 8).split(":") + return "".join([f"0x{s}, " + ("\n\t" if i % 8 == 7 else "") for i, s in enumerate(hex_str)]) def set_addr(self, startAddress): startAddress = get64bitAlignedAddr(startAddress) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 9b80aa0dd..a767e7fff 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1,5 +1,6 @@ from typing import Union, Optional from dataclasses import dataclass, field +import numpy as np # included by blender import bpy from math import ceil, floor @@ -563,7 +564,7 @@ def writeAll( self.texProp.tex, fImage, self.pal, self.palFormat, self.texFormat, f3d.F3DZEX2_EMU64 ) else: - writeNonCITextureData(self.texProp.tex, fImage, self.texFormat) + writeNonCITextureData(self.texProp.tex, fImage, self.texFormat, f3d.F3DZEX2_EMU64) class MultitexManager: @@ -632,13 +633,13 @@ def writeAll( if fModel.f3d.F3DZEX2_EMU64: non_rgba = False if self.ti0.useTex: - if self.ti0.pal: + if self.ti0.pal is not None: self.ti0.palIndex = 15 # The default pallete index in AC is 15 self.ti0.palLen = len(self.ti0.pal) self.ti0.loadPal = True non_rgba = self.ti0.palFormat != "RGBA16" if self.ti1.useTex: - if self.ti1.pal: + if self.ti1.pal is not None: self.ti1.palIndex = 15 - 1 self.ti1.palLen = len(self.ti1.pal) self.ti1.loadPal = True @@ -1118,6 +1119,39 @@ def savePaletteLoad( # Functions for converting and writing texture and palette data +def get_rgba16_colors(pixels): # 5 bit RGB, 1 bit alpha + rgb5b = np.round(pixels[:, :3] * (2**5 - 1)).astype(np.uint16) + return (rgb5b[:, 0] << 11) | (rgb5b[:, 1] << 6) | (rgb5b[:, 2] << 1) | (pixels[:, 3] > 0.5) + + +def get_rgb5a3_colors(pixels): + """Each pixel can either be 5 bit RGB (opaque) or 4 bit RGB 3 bit alpha. + The upper 16th bit defines if a pixel is fully opaque, + therefor ignoring the other 3 bits that would otherwise be used for alpha.""" + opaque_mask = pixels[:, 3] == 255 + rgb5 = np.round(pixels[:, :3] * (2**5 - 1)).astype(np.uint16) + rgb4 = np.round(pixels[:, :3] * (2**4 - 1)).astype(np.uint16) + opaque_pixels = (1 << 15) | ((rgb5[:, 0] >> 3) << 10) | ((rgb5[:, 1] >> 3) << 5) | (rgb5[:, 2] >> 3) + translucent_pixels = ( + np.round(pixels[:, 3] * (2**3 - 1)).astype(np.uint16) + | ((rgb4[:, 0] >> 4) << 8) + | ((rgb4[:, 1] >> 4) << 4) + | (rgb4[:, 2] >> 4) + ) + return np.where(opaque_mask, opaque_pixels, translucent_pixels) + + +def get_ia_colors(pixels, i_bits=8, a_bits=8): + size = max(8, i_bits + a_bits) + i_max, a_max = 2**i_bits - 1, 2**a_bits - 1 + assert hasattr(np, f"uint{size}"), f"Invalid size {size}" + typ = getattr(np, f"uint{size}") + result = (color_to_luminance_np(pixels) * i_max).round().astype(typ) + if a_bits > 0: + return result << a_bits | (pixels[:, 3] * a_max).round().astype(typ) + return result + + def extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb): color = [1, 1, 1, 1] for field in range(image.channels): @@ -1131,126 +1165,121 @@ def extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb): return pixelColor +def image_to_ci_texture(image, palFormat, use_argb): + pixels = get_pixels_from_image(image) + if palFormat == "RGBA16": + if use_argb: + return get_rgb5a3_colors(pixels) + else: + return get_rgba16_colors(pixels) + elif palFormat == "IA16": + return get_ia_colors(pixels) + raise PluginError(f"Internal error, palette format is {palFormat}") + + def getColorsUsedInImage(image, palFormat, use_argb): - palette = [] - # N64 is -Y, Blender is +Y - pixels = image.pixels[:] - for j in reversed(range(image.size[1])): - for i in range(image.size[0]): - pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb) - if pixelColor not in palette: - palette.append(pixelColor) - return palette + return np.sort(np.unique(image_to_ci_texture(image, palFormat, use_argb))) def mergePalettes(pal0, pal1): - palette = [c for c in pal0] - for c in pal1: - if c not in palette: - palette.append(c) - return palette + return np.sort(np.unique(np.concatenate((pal0, pal1)))) + + +def getColorIndicesOfTexture(image, sorted_palette, palFormat, use_argb): + return np.searchsorted(sorted_palette, image_to_ci_texture(image, palFormat, use_argb)).astype(np.uint8) -def getColorIndicesOfTexture(image, palette, palFormat, use_argb): - texture = [] - # N64 is -Y, Blender is +Y - pixels = image.pixels[:] - for j in reversed(range(image.size[1])): - for i in range(image.size[0]): - pixelColor = extractConvertCIPixel(image, pixels, i, j, palFormat, use_argb) - if pixelColor not in palette: - raise PluginError(f"Bug: {image.name} palette len {len(palette)} missing CI") - texture.append(palette.index(pixelColor)) - return texture +def writePaletteData(fPalette: FImage, palette: list[int]): + if fPalette.converted: + return + fPalette.data = palette + fPalette.converted = True -def compactNibbleArray(texture, width, height): - nibbleData = bytearray(0) - dataSize = int(width * height / 2) +def emu64_swizzle_pixels(input_list: np.ndarray[Any, (Any, 4)], width: int, height: int, fmt: str): + block_w, block_h = EMU64_SWIZZLE_SIZES[texBitSizeF3D[fmt]] + block_x_count = width // block_w + block_y_count = height // block_h + output_buffer = np.empty((height * width, 4), input_list.dtype) + i = 0 - nibbleData = [((texture[i * 2] & 0xF) << 4) | (texture[i * 2 + 1] & 0xF) for i in range(dataSize)] + for y_block in reversed(range(block_y_count)): + for x_block in range(block_x_count): + for y_pixel in reversed(range(block_h)): + for x_pixel in range(block_w): + pixel_index = (width * block_h * y_block) + y_pixel * width + x_block * block_w + x_pixel + output_buffer[i] = input_list[pixel_index] + i += 1 - if (width * height) % 2 == 1: - nibbleData.append((texture[-1] & 0xF) << 4) + return output_buffer - return bytearray(nibbleData) +def get_pixels_from_image(image: bpy.types.Image) -> np.ndarray[np.float32, (Any, 4)]: + channel_count = image.channels + width, height = image.size -def writePaletteData(fPalette: FImage, palette: list[int]): - if fPalette.converted: - return - for color in palette: - fPalette.data.extend(color.to_bytes(2, "big")) - fPalette.converted = True + bpy_pixels = np.array(image.pixels, dtype=np.float32).reshape((height, width, channel_count)).clip(0.0, 1.0) + result = np.ones((image.size[1], image.size[0], 4), dtype=np.float32) # default to white opaque + result[:, :, :channel_count] = bpy_pixels # copy, if channel count is 3 all alpha channels will stay 1 + result = np.flip(result, 0) # N64 is -Y, Blender is +Y + result = result.reshape((height * width, 4)) # flatten pixels + + return result + + +def compact_nibble_np(pixels: np.ndarray[np.uint8, Any]): + if len(pixels) % 2 != 0: # uneven pixel count. this is uncommon, don't bother with a more opt approach + pixels = np.append(pixels, pixels[-1]) + return (pixels[::2] << 4) | pixels[1::2] def writeCITextureData( - image: bpy.types.Image, fImage: FImage, palette: list[int], palFmt: str, texFmt: str, use_argb: bool + image: bpy.types.Image, fImage: FImage, palette: list[int], palFmt: str, texFmt: str, emu64: bool ): if fImage.converted: return - texture = getColorIndicesOfTexture(image, palette, palFmt, use_argb) + pixels = getColorIndicesOfTexture(image, palette, palFmt, emu64) + if emu64: + pixels = emu64_swizzle_pixels(np.array(pixels, dtype=np.uint8), image.size[0], image.size[1], texFmt) if texFmt == "CI4": - fImage.data = compactNibbleArray(texture, image.size[0], image.size[1]) + fImage.data = np.array(compact_nibble_np(np.array(pixels, dtype=np.uint8)), dtype=np.uint8) else: - fImage.data = bytearray(texture) + fImage.data = pixels + fImage.converted = True -def writeNonCITextureData(image: bpy.types.Image, fImage: FImage, texFmt: str): +def writeNonCITextureData(image: bpy.types.Image, fImage: FImage, texFmt: str, emu64: bool): if fImage.converted: return fmt = texFormatOf[texFmt] bitSize = texBitSizeF3D[texFmt] - pixels = image.pixels[:] + pixels = get_pixels_from_image(image) + if emu64: + pixels = emu64_swizzle_pixels(pixels, image.size[0], image.size[1], texFmt) if fmt == "G_IM_FMT_RGBA": - if bitSize == "G_IM_SIZ_16b": - fImage.data = bytearray( - [ - byteVal - for doubleByte in [ - ( - ( - ((int(round(pixels[(j * image.size[0] + i) * image.channels + 0] * 0x1F)) & 0x1F) << 3) - | ( - (int(round(pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F)) & 0x1F) - >> 2 - ) - ), - ( - ((int(round(pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F)) & 0x03) << 6) - | ( - (int(round(pixels[(j * image.size[0] + i) * image.channels + 2] * 0x1F)) & 0x1F) - << 1 - ) - | (1 if pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) - ), - ) - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - for byteVal in doubleByte - ] - ) - elif bitSize == "G_IM_SIZ_32b": - fImage.data = bytearray( - [ - int(round(pixels[(j * image.size[0] + i) * image.channels + field] * 0xFF)) & 0xFF - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - for field in range(image.channels) - ] - ) + if bitSize == "G_IM_SIZ_16b": # 5 bit RGB, 1 bit alpha + fImage.data = get_rgba16_colors(pixels) + elif bitSize == "G_IM_SIZ_32b": # 8 bit RGBA + fImage.data = (pixels * 0xFF).round().astype(np.uint8) else: raise PluginError("Invalid combo: " + fmt + ", " + bitSize) elif fmt == "G_IM_FMT_YUV": - raise PluginError("YUV not yet implemented.") - if bitSize == "G_IM_SIZ_16b": - pass + if bitSize == "G_IM_SIZ_16b": # 4 bit Y, 2 bit UV + # https://gist.github.com/Quasimondo/c3590226c924a06b276d606f4f189639 + m = np.array([[0.29900, -0.16874, 0.50000], [0.58700, -0.33126, -0.41869], [0.11400, 0.50000, -0.08131]]) + + pixels: np.ndarray[Any, 3] = np.dot(pixels[:, :3], m) + pixels[:, 1:] += 0.5 + fImage.data = ( + (pixels[:, 0] * 0xFF).round().astype(np.uint16) << 8 + | (pixels[:, 1] * 0xF).round().astype(np.uint16) << 4 + | (pixels[:, 2] * 0xF).round().astype(np.uint16) + ) else: raise PluginError("Invalid combo: " + fmt + ", " + bitSize) @@ -1258,136 +1287,22 @@ def writeNonCITextureData(image: bpy.types.Image, fImage: FImage, texFmt: str): raise PluginError("Internal error, writeNonCITextureData called for CI image.") elif fmt == "G_IM_FMT_IA": - if bitSize == "G_IM_SIZ_4b": - fImage.data = bytearray( - [ - ( - ( - int( - round( - colorToLuminance( - pixels[ - (j * image.size[0] + i) - * image.channels : (j * image.size[0] + i) - * image.channels - + 3 - ] - ) - * 0x7 - ) - ) - & 0x7 - ) - << 1 - ) - | (1 if pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - ) - elif bitSize == "G_IM_SIZ_8b": - fImage.data = bytearray( - [ - ( - ( - int( - round( - colorToLuminance( - pixels[ - (j * image.size[0] + i) - * image.channels : (j * image.size[0] + i) - * image.channels - + 3 - ] - ) - * 0xF - ) - ) - & 0xF - ) - << 4 - ) - | (int(round(pixels[(j * image.size[0] + i) * image.channels + 3] * 0xF)) & 0xF) - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - ) - elif bitSize == "G_IM_SIZ_16b": - fImage.data = bytearray( - [ - byteVal - for doubleByte in [ - ( - int( - round( - colorToLuminance( - pixels[ - (j * image.size[0] + i) - * image.channels : (j * image.size[0] + i) - * image.channels - + 3 - ] - ) - * 0xFF - ) - ) - & 0xFF, - int(round(pixels[(j * image.size[0] + i) * image.channels + 3] * 0xFF)) & 0xFF, - ) - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - for byteVal in doubleByte - ] - ) + if bitSize == "G_IM_SIZ_4b": # 3 bit intensity, 1 bit alpha + fImage.data = compact_nibble_np(get_ia_colors(pixels, i_bits=3, a_bits=1)) + elif bitSize == "G_IM_SIZ_8b": # 4 bit intensity, 4 bit alpha + fImage.data = get_ia_colors(pixels, i_bits=4, a_bits=4) + elif bitSize == "G_IM_SIZ_16b": # 8 bit intensity, 8 bit alpha + fImage.data = get_ia_colors(pixels) else: raise PluginError("Invalid combo: " + fmt + ", " + bitSize) elif fmt == "G_IM_FMT_I": - if bitSize == "G_IM_SIZ_4b": - fImage.data = bytearray( - [ - int( - round( - colorToLuminance( - pixels[ - (j * image.size[0] + i) * image.channels : (j * image.size[0] + i) * image.channels - + 3 - ] - ) - * 0xF - ) - ) - & 0xF - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - ) - elif bitSize == "G_IM_SIZ_8b": - fImage.data = bytearray( - [ - int( - round( - colorToLuminance( - pixels[ - (j * image.size[0] + i) * image.channels : (j * image.size[0] + i) * image.channels - + 3 - ] - ) - * 0xFF - ) - ) - & 0xFF - for j in reversed(range(image.size[1])) - for i in range(image.size[0]) - ] - ) + if bitSize == "G_IM_SIZ_4b": # 4 bit intensity + fImage.data = compact_nibble_np(get_ia_colors(pixels, i_bits=4, a_bits=0)) + elif bitSize == "G_IM_SIZ_8b": # 8 bit intensity + fImage.data = get_ia_colors(pixels, i_bits=8, a_bits=0) else: raise PluginError("Invalid combo: " + fmt + ", " + bitSize) else: raise PluginError("Invalid image format " + fmt) - # We stored 4bit values in byte arrays, now to convert - if bitSize == "G_IM_SIZ_4b": - fImage.data = compactNibbleArray(fImage.data, image.size[0], image.size[1]) - fImage.converted = True diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 0db4804ec..00391f930 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -1,6 +1,7 @@ import bpy, random, string, os, math, traceback, re, os, mathutils, ast, operator from math import pi, ceil, degrees, radians, copysign from mathutils import * +import numpy as np from .utility_anim import * from typing import Callable, Iterable, Any, Optional, Tuple, TypeVar, Union from bpy.types import UILayout, Scene, World @@ -575,7 +576,7 @@ def get_rgb5a3_color(color): r, g, b, a = round(color[0] * 255), round(color[1] * 255), round(color[2] * 255), round(color[3] * 255) if a == 255: # Opaque, upper bit is 1 return (1 << 15) | ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3) - else: + else: # rgb 4 bits, a 3 bits return ((a >> 5) << 12) | ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4) @@ -588,6 +589,10 @@ def colorToLuminance(color: mathutils.Color | list[float] | Vector): return RGB_TO_LUM_COEF.dot(color[:3]) +def color_to_luminance_np(pixels: np.ndarray[Any, 4]) -> np.ndarray[Any, 1]: + return np.dot(pixels[:, :3], RGB_TO_LUM_COEF) + + def getIA16Tuple(color): intensity = colorToLuminance(color[0:3]) alpha = color[3] From 9fcf22213f2889e8a8cfed43674b3cb92fecb88c Mon Sep 17 00:00:00 2001 From: Lila Date: Thu, 26 Dec 2024 00:47:22 +0000 Subject: [PATCH 82/82] fix large texture mode --- fast64_internal/f3d/f3d_texture_writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast64_internal/f3d/f3d_texture_writer.py b/fast64_internal/f3d/f3d_texture_writer.py index 01d176047..f0c377425 100644 --- a/fast64_internal/f3d/f3d_texture_writer.py +++ b/fast64_internal/f3d/f3d_texture_writer.py @@ -1077,7 +1077,7 @@ def saveTextureTile( if f3d.F3DZEX2_EMU64: if (clamp_S and mirror_S) or (clamp_T and mirror_T): raise PluginError("Clamp + mirror not supported in F3DZEX2 (Emu64)") - if tileSettings and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): + if tileSettings is None and (log2iRoundUp(fImage.width) != masks or log2iRoundUp(fImage.height) != maskt): raise PluginError("Mask is not emulated in emu64, non default values are not supported") wrap_s = "GX_CLAMP" if clamp_S else "GX_MIRROR" if mirror_S else "GX_REPEAT" wrap_t = "GX_CLAMP" if clamp_T else "GX_MIRROR" if mirror_T else "GX_REPEAT"