2022-07-19 14:04:54 +01:00
|
|
|
#!/usr/bin/python3
|
|
|
|
|
|
2023-09-21 14:13:58 -05:00
|
|
|
import sys, subprocess, re
|
2022-07-19 14:04:54 +01:00
|
|
|
|
|
|
|
|
if len(sys.argv) != 2:
|
|
|
|
|
print(f"Usage: {sys.argv[0]} [folder to search]")
|
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
|
|
lightFiles = set()
|
|
|
|
|
|
|
|
|
|
# The original command that was run across the entire repo to convert all assets
|
|
|
|
|
# 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
|
2023-09-21 14:13:58 -05:00
|
|
|
cmds = [
|
|
|
|
|
f"grep -Rl \"gsSPSetLight\" {sys.argv[1]}",
|
|
|
|
|
f"grep -Rl \"gsSPLight\" {sys.argv[1]}",
|
|
|
|
|
f"grep -Rl \"Lights1\" {sys.argv[1]}"
|
|
|
|
|
]
|
2022-07-19 14:04:54 +01:00
|
|
|
|
|
|
|
|
for cmd in cmds:
|
|
|
|
|
try:
|
2023-09-21 14:13:58 -05:00
|
|
|
output = subprocess.check_output(cmd, shell=True).decode('UTF-8').split("\n")[:-1]
|
2022-07-19 14:04:54 +01:00
|
|
|
lightFiles = set.union(lightFiles,set(output))
|
|
|
|
|
except subprocess.CalledProcessError:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
lightStructs = {}
|
2023-09-21 14:13:58 -05:00
|
|
|
# FIRST PASS: COLLECT LIGHT STRUCT INFO, REMOVE LIGHT STRUCTS
|
2022-07-19 14:04:54 +01:00
|
|
|
for file in lightFiles:
|
|
|
|
|
changed = False
|
|
|
|
|
with open(file, "r") as f:
|
|
|
|
|
fileLines = f.readlines()
|
|
|
|
|
index = 0
|
2023-09-21 14:13:58 -05:00
|
|
|
|
2022-07-19 14:04:54 +01:00
|
|
|
while index < len(fileLines):
|
|
|
|
|
curLine = fileLines[index].strip()
|
2023-09-21 14:13:58 -05:00
|
|
|
|
2022-07-19 14:04:54 +01:00
|
|
|
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
|
|
|
|
|
args = ""
|
|
|
|
|
while not ")" in fileLines[index]:
|
|
|
|
|
args += fileLines[index].strip()
|
|
|
|
|
del fileLines[index]
|
|
|
|
|
del fileLines[index] # Remove ending line
|
|
|
|
|
args = args.strip(");")
|
|
|
|
|
args = [int(arg.strip()[2:],16) for arg in args.split(",")]
|
|
|
|
|
lightStructs[structName] = args
|
|
|
|
|
changed = True
|
|
|
|
|
elif "Lights1" in curLine and "gdSPDefLights1" in curLine:
|
|
|
|
|
structName = curLine.split("Lights1")[1].strip().split(" ")[0] # Get string between Lights 1 and following space
|
|
|
|
|
del fileLines[index] # Remove beginning
|
|
|
|
|
args = ""
|
|
|
|
|
while True:
|
|
|
|
|
args += fileLines[index].strip()
|
|
|
|
|
if ")" in fileLines[index]:
|
|
|
|
|
break
|
|
|
|
|
del fileLines[index]
|
|
|
|
|
del fileLines[index] # Remove ending line
|
|
|
|
|
args = args.strip(");")
|
|
|
|
|
args = [int(arg.strip()[2:],16) for arg in args.split(",")]
|
|
|
|
|
lightStructs[structName] = args
|
|
|
|
|
changed = True
|
|
|
|
|
|
|
|
|
|
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)
|
2023-09-21 14:13:58 -05:00
|
|
|
|
|
|
|
|
# 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,))
|
|
|
|
|
|
2022-07-19 14:04:54 +01:00
|
|
|
# SECOND PASS - CHANGE LIGHT COMMANDS
|
|
|
|
|
for file in lightFiles:
|
|
|
|
|
changed = False
|
|
|
|
|
with open(file, "r") as f:
|
|
|
|
|
fileLines = f.readlines()
|
|
|
|
|
index = 0
|
2023-09-21 14:13:58 -05:00
|
|
|
dl_index = -1
|
2022-07-19 14:04:54 +01:00
|
|
|
while index < len(fileLines):
|
|
|
|
|
curLine = fileLines[index].strip()
|
2023-09-21 14:13:58 -05:00
|
|
|
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
|
2022-07-19 14:04:54 +01:00
|
|
|
|
|
|
|
|
if curLine.startswith("gsSPSetLights1("):
|
|
|
|
|
structName = curLine.split("(")[1].split(")")[0] # Get string between ( and )
|
|
|
|
|
if structName in lightStructs.keys():
|
|
|
|
|
changed = True
|
|
|
|
|
args = lightStructs[structName]
|
|
|
|
|
light1Args = args[3]*0x1000000 + args[4]*0x10000 + args[5]*0x100 + 0xFF
|
|
|
|
|
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)
|
2023-09-21 14:13:58 -05:00
|
|
|
index_delta(curDL, dl_index, 1)
|
|
|
|
|
dl_index += 2 # gsSPSetLights1 expands to 3 commands, gsSPLightColor is 2 commands each
|
2022-07-19 14:04:54 +01:00
|
|
|
index += 1
|
|
|
|
|
else:
|
|
|
|
|
print("Missing light definition %s in file %s. Skipping..." % (structName, file))
|
2023-09-21 14:13:58 -05:00
|
|
|
|
2022-07-19 14:04:54 +01:00
|
|
|
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))
|
|
|
|
|
index += 1
|
|
|
|
|
continue
|
|
|
|
|
structName = curLine.split("&")[1].split(".")[0] # Get string between & and . (&lightname.l or &lightname.a)
|
|
|
|
|
if structName in lightStructs.keys():
|
|
|
|
|
changed = True
|
|
|
|
|
args = lightStructs[structName]
|
|
|
|
|
lightNum = int(curLine.split(",")[1].strip()[0]) # , 1),
|
|
|
|
|
argIndex = (3 if lightNum == 1 else 0)
|
|
|
|
|
lightArgs = args[argIndex]*0x1000000 + args[argIndex+1]*0x10000 + args[argIndex+2]*0x100 + 0xFF
|
|
|
|
|
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))
|
2023-09-21 14:13:58 -05:00
|
|
|
|
2022-07-19 14:04:54 +01:00
|
|
|
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)
|
|
|
|
|
|
2023-09-21 14:13:58 -05:00
|
|
|
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)
|