From 60bb21693bea7562a78a94a317f791838af6a6b1 Mon Sep 17 00:00:00 2001 From: thecozies <79979276+thecozies@users.noreply.github.com> Date: Thu, 21 Sep 2023 14:13:58 -0500 Subject: [PATCH] fix tile scrolled light materials (#687) --- tools/fixlights.py | 109 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/tools/fixlights.py b/tools/fixlights.py index 87f12739..c869b992 100755 --- a/tools/fixlights.py +++ b/tools/fixlights.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -import sys, subprocess +import sys, subprocess, re if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} [folder to search]") @@ -12,25 +12,30 @@ lightFiles = set() # cmds = ("grep -Rl \"gsSPSetLight\" levels actors bin","grep -Rl \"gsSPLight\" levels actors bin","grep -Rl \"Lights1\" levels actors bin") # Operate on the folder passed as an argument to this program -cmds = [f"grep -Rl \"gsSPSetLight\" {sys.argv[1]}",f"grep -Rl \"gsSPLight\" {sys.argv[1]}",f"grep -Rl \"Lights1\" {sys.argv[1]}"] +cmds = [ + f"grep -Rl \"gsSPSetLight\" {sys.argv[1]}", + f"grep -Rl \"gsSPLight\" {sys.argv[1]}", + f"grep -Rl \"Lights1\" {sys.argv[1]}" +] for cmd in cmds: try: - output = subprocess.check_output(cmd, shell=True).decode('UTF-8').split("\n")[:-1] + output = subprocess.check_output(cmd, shell=True).decode('UTF-8').split("\n")[:-1] lightFiles = set.union(lightFiles,set(output)) except subprocess.CalledProcessError: continue lightStructs = {} -# FIRST PASS: COLLECT LIGHT STRUCT INFO, REMOVE LIGHT STRUCTS +# FIRST PASS: COLLECT LIGHT STRUCT INFO, REMOVE LIGHT STRUCTS for file in lightFiles: changed = False with open(file, "r") as f: fileLines = f.readlines() index = 0 + while index < len(fileLines): curLine = fileLines[index].strip() - + if "const Lights1" in curLine and "gdSPDefLights1" in curLine: structName = curLine.split("const Lights1")[1].strip().split(" ")[0] # Get string between Lights 1 and following space del fileLines[index] # Remove beginning @@ -63,15 +68,32 @@ for file in lightFiles: if changed: with open(file, "w") as f: f.writelines(fileLines) - + +# material diffs at lines for correcting fast64 tile scroll exports +material_deltas = {} +def index_delta(mat_name, orig_index, delta): + if mat_name not in material_deltas: + material_deltas[mat_name] = [] + + material_deltas[mat_name].append((orig_index, delta,)) + # SECOND PASS - CHANGE LIGHT COMMANDS for file in lightFiles: changed = False with open(file, "r") as f: fileLines = f.readlines() index = 0 + dl_index = -1 while index < len(fileLines): curLine = fileLines[index].strip() + dl_index += 1 + + match_result = re.search("Gfx\s*([A-Za-z_]\w+)\s*\[\s*\w*\s*\]\s*=\s*\{", curLine) + if match_result is not None and len(match_result.groups()) >= 1: + curDL = match_result.group(1) + dl_index = -1 + index += 1 + continue if curLine.startswith("gsSPSetLights1("): structName = curLine.split("(")[1].split(")")[0] # Get string between ( and ) @@ -82,10 +104,12 @@ for file in lightFiles: light2Args = args[0]*0x1000000 + args[1]*0x10000 + args[2]*0x100 + 0xFF fileLines[index] = " gsSPLightColor(LIGHT_1, 0x%x),\n" % light1Args fileLines.insert(index+1," gsSPLightColor(LIGHT_2, 0x%x),\n" % light2Args) + index_delta(curDL, dl_index, 1) + dl_index += 2 # gsSPSetLights1 expands to 3 commands, gsSPLightColor is 2 commands each index += 1 else: print("Missing light definition %s in file %s. Skipping..." % (structName, file)) - + elif curLine.startswith("gsSPLight("): if not "&" in curLine or not "." in curLine: print("Malformed gsSPLight command in file %s, line %d. Skipping..." % (file, index+1)) @@ -101,10 +125,79 @@ for file in lightFiles: fileLines[index] = " gsSPLightColor(LIGHT_%d, 0x%x),\n" % (lightNum, lightArgs) else: print("Missing light definition %s in file %s, line %d. Skipping..." % (structName, file, index+1)) - + index += 1 # Don't write to the file if the contents haven't been changed, as this will trigger a rebuild by Make if changed: with open(file, "w") as f: f.writelines(fileLines) +def get_texscroll_files(): + mat_grep_commands = [] + for mat in material_deltas.keys(): + print("grep -Rl \"segmented_to_virtual(" + re.escape(mat) + f"\" {sys.argv[1]}**/texscroll.inc.c") + mat_grep_commands.append("grep -Rl \"segmented_to_virtual(" + re.escape(mat) + f"\" {sys.argv[1]} --include \*texscroll*") + + texscroll_files = set() + for cmd in mat_grep_commands: + try: + output = subprocess.check_output(cmd, shell=True).decode('UTF-8').split("\n")[:-1] + texscroll_files = set.union(texscroll_files,set(output)) + except subprocess.CalledProcessError: + continue + + return texscroll_files + +t_files = get_texscroll_files() +t_mats = set(material_deltas.keys()) + +# 3RD PASS: Update fast64 generated texscroll files +for file in t_files: + changed = False + with open(file, "r") as f: + fileLines = f.readlines() + in_func = False + found_mat_match = False + mat_match = None + for index in range(len(fileLines)): + curLineFull = fileLines[index] + curLine = curLineFull.strip() + + if not in_func: + match_result = re.search("void \w+\(\) \{", curLine) + in_func = match_result is not None + found_mat_match = False + continue + elif curLineFull.startswith("}"): + in_func = False + found_mat_match = False + continue + + if not found_mat_match: + match_result = re.search("Gfx \*mat = segmented_to_virtual\((\w*)\)", curLine) + if not match_result: + continue + + seg_mat = match_result.group(1) + if seg_mat in t_mats: + found_mat_match = True + mat_match = seg_mat + continue + + match_result = re.search("shift_\w*\(mat, (\d*),", curLine) + if match_result is not None and len(match_result.groups()) >= 1: + sts_index_str = match_result.group(1) + sts_index = int(sts_index_str) + print(sts_index, curLine) + new_sts_index = sts_index + for orig_index, delta in material_deltas[mat_match]: + if orig_index > sts_index: + break + new_sts_index += delta + fileLines[index] = curLineFull.replace(f"mat, {sts_index_str}, ", f"mat, {new_sts_index}, ") + changed = True + + # Don't write to the file if the contents haven't been changed, as this will trigger a rebuild by Make + if changed: + with open(file, "w") as f: + f.writelines(fileLines)