Skip to content

Commit 01a274e

Browse files
adding TrenchBroom support & more transparent materials
1 parent 9e7df33 commit 01a274e

File tree

1 file changed

+71
-32
lines changed

1 file changed

+71
-32
lines changed

batch.py

+71-32
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
# see VTFLibWrapper/README.md for links to Linux version
1717

1818

19-
__version__ = "1.0.0"
19+
__version__ = "1.1.0"
2020
# NOTE: cannot be bothered to convert .vmt proxies
2121
# TODO: Titanfall 2 rpak .json materials -> .shader
2222

2323

2424
patterns = {"alphatest": re.compile(r'\s"\$alphatest"\s1'),
2525
"basetexture": re.compile(r'\s"\$basetexture"\s"(.*)"'),
26-
"tooltexture": re.compile(r'\s%tooltexture\s"(.*)"')}
26+
"tooltexture": re.compile(r'\s%tooltexture\s"(.*)"'),
27+
"translucent": re.compile(r'\s"\$translucent"\s"1"')}
2728

2829

2930
class VMT:
@@ -36,14 +37,18 @@ def from_file(cls, filename: str) -> VMT:
3637
out = cls()
3738
with open(filename) as vmt_file:
3839
for line in vmt_file:
39-
if re.match(patterns["alphatest"], line) is not None:
40-
out.is_trans = True
41-
match = re.match(patterns["basetexture"], line)
42-
if match is not None:
43-
out.basetexture = match.groups()[0]
44-
match = re.match(patterns["tooltexture"], line)
45-
if match is not None:
46-
out.tooltexture = match.groups()[0]
40+
for check, pattern in patterns.items():
41+
match = re.match(pattern, line)
42+
if match is None:
43+
continue
44+
if check in ("alphatest", "translucent"):
45+
out.is_trans = True
46+
elif check == "basetexture":
47+
out.basetexture = match.groups()[0]
48+
elif check == "tooltexture":
49+
out.tooltexture = match.groups()[0]
50+
else:
51+
raise NotImplementedError(f"i forgor {check}")
4752
return out
4853

4954

@@ -60,17 +65,15 @@ def filename(folder: str, base: str, ext: str) -> str:
6065
return os.path.join(folder, f"{base}.{ext}")
6166

6267

63-
# TODO: textures -> shader_names for TrenchBroom
64-
def convert_folder(materials_dir: str, MRVN_dir: str, MRVN_game: str,
65-
recursive=False, subfolder: str = "", verbose=False):
66-
# e.g. "../titanfall1_extracted_textures", "C:/MRVN-radiant", "titanfallonline"
67-
materials_dir = os.path.realpath(materials_dir)
68-
MRVN_dir = os.path.realpath(MRVN_dir)
69-
scripts_dir = os.path.join(MRVN_dir, MRVN_game, "scripts")
70-
textures_dir = os.path.join(MRVN_dir, MRVN_game, "textures")
71-
# NOTE: just directly grab all the world textures
72-
top_folder = os.path.join(materials_dir, "world", subfolder)
73-
for folder in os.listdir(os.path.join(materials_dir, "world", subfolder)):
68+
# MRVN-radiant
69+
def convert_folder(materials_dir: str, titanfall_dir: str, subfolder: str = "", recurse=False, verbose=False):
70+
# e.g. "../titanfall1_extracted_textures", "C:/MRVN-radiant/titanfallonline"
71+
materials_dir = os.path.realpath(materials_dir) # src
72+
titanfall_dir = os.path.realpath(titanfall_dir) # dest
73+
scripts_dir = os.path.join(titanfall_dir, "scripts")
74+
textures_dir = os.path.join(titanfall_dir, "textures")
75+
top_folder = os.path.join(materials_dir, subfolder)
76+
for folder in os.listdir(top_folder):
7477
vmt_folder = os.path.join(top_folder, folder)
7578
if not os.path.isdir(vmt_folder):
7679
continue
@@ -87,17 +90,15 @@ def convert_folder(materials_dir: str, MRVN_dir: str, MRVN_game: str,
8790
if verbose:
8891
print(f"!!! {vmt_filename} has no texture !!!")
8992
continue
90-
shader_name = os.path.join("textures", "world", subfolder, folder, vmt_filename[:-4])
93+
shader_name = os.path.join("textures", subfolder, folder, vmt_filename[:-4])
9194
shader_file.write(f"\n{shader_name}\n" + "{\n")
92-
# shader_file.write(f"\tqer_editorimage {shader_name}.tga\n")
9395
texture = vmt.basetexture if vmt.tooltexture is None else vmt.tooltexture
9496
shader_file.write(f"\tqer_editorimage {os.path.join('textures', texture)}.tga\n")
9597
# TODO: convert as much of the shader as possible
9698
if vmt.is_trans:
97-
# NOTE: should really target basetexture, but we rename it later
98-
shader_file.write("\t{\n\t\tmap " + os.path.join("textures", shader_name) + ".tga\n")
99+
shader_file.write("\tqer_trans 1.00\n") # use texture alpha
99100
# shader_file.write("\t{\n\t\tmap " + os.path.join("textures", vmt.basetexture) + ".tga\n")
100-
shader_file.write("\t\tblendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA\n\t}\n")
101+
# shader_file.write("\t\tblendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA\n\t}\n")
101102
shader_file.write("}\n")
102103
# .vtf
103104
vtf_filename = filename(materials_dir, texture, "vtf")
@@ -117,24 +118,62 @@ def convert_folder(materials_dir: str, MRVN_dir: str, MRVN_game: str,
117118
print(f"--- {count} materials converted")
118119
if count == 0:
119120
os.remove(os.path.realpath(shader_file.name))
120-
if recursive:
121-
convert_folder(materials_dir, MRVN_dir, MRVN_game, True, os.path.join(subfolder, folder), verbose=verbose)
121+
if recurse:
122+
convert_folder(materials_dir, titanfall_dir, os.path.join(subfolder, folder), True, verbose=verbose)
123+
124+
125+
# TrenchBroom
126+
def convert_folder_trenchbroom(materials_dir: str, tga_dir: str, subfolder: str = "", recurse=False, verbose=False):
127+
# e.g. "../titanfall1_extracted_textures", ".../TrenchBroom maps/Titanfall/textures"
128+
# NOTE: subfolder should be a subfolder of materials
129+
# NOTE: no .shader; straight to 1 .tga per material name
130+
materials_dir = os.path.realpath(materials_dir) # src
131+
tga_dir = os.path.realpath(tga_dir) # dest
132+
top_folder = os.path.join(materials_dir, subfolder)
133+
for folder in os.listdir(top_folder):
134+
vmt_folder = os.path.join(top_folder, folder)
135+
if not os.path.isdir(vmt_folder):
136+
continue
137+
count = 0
138+
for vmt_filename in fnmatch.filter(os.listdir(vmt_folder), "*.vmt"):
139+
# .vmt
140+
vmt = VMT.from_file(os.path.join(vmt_folder, vmt_filename))
141+
if vmt.basetexture == "" and vmt.tooltexture is None:
142+
if verbose:
143+
print(f"!!! {vmt_filename} has no texture !!!")
144+
continue
145+
shader_name = os.path.join("textures", "world", subfolder, folder, vmt_filename[:-4])
146+
texture = vmt.basetexture if vmt.tooltexture is None else vmt.tooltexture
147+
# .vtf
148+
vtf_filename = filename(materials_dir, texture, "vtf")
149+
if not os.path.exists(vtf_filename):
150+
if verbose:
151+
print(f"!!! {vmt_filename} texture {texture} not found !!!")
152+
continue
153+
vtf_to_tga(vtf_filename, filename(tga_dir, shader_name, "tga"))
154+
count += 1
155+
if verbose:
156+
print(f"--- {count} materials converted")
157+
if recurse:
158+
convert_folder_trenchbroom(materials_dir, tga_dir, True, os.path.join(subfolder, folder), verbose=verbose)
122159

123160

124161
if __name__ == "__main__":
125162
import sys
126163

127164
# materials_dir = "E:/Mod/TitanfallOnline/TitanFallOnline/assets_dump/materials"
128-
# MRVN_dir = "E:/Mod/_tools/Source Engine - Respawn/MRVN-radiant-3db242a-Windows-x86_64"
165+
# titanfall_dir = "E:/Mod/_tools/Source Engine - Respawn/MRVN-radiant-3db242a-Windows-x86_64/titanfallonline"
129166
if len(sys.argv) == 3:
130-
materials_dir, MRVN_dir = sys.argv[1:]
167+
materials_dir, titanfall_dir = sys.argv[1:]
131168
# elif len(sys.argv) == 1:
132169
# pass # use defaults
133170
else:
134-
print(f'Usage: {sys.argv[0]} "Titanfall materials dir" "MRVN-radiant install dir"')
171+
print(f'Usage: {sys.argv[0]} "Titanfall materials dir" "MRVN-radiant working titanfall dir"')
135172
print('\tif you can\'t find your "Titanfall/materials" folder, extract it from the .vpks')
136173
sys.exit()
137174

138175
sys.stdout.reconfigure(line_buffering=True) # for piping print to logfile
139-
convert_folder(materials_dir, MRVN_dir, "titanfallonline", True, verbose=True)
176+
convert_folder(materials_dir, titanfall_dir, subfolder="dev", recurse=True, verbose=True)
177+
convert_folder(materials_dir, titanfall_dir, subfolder="world", recurse=True, verbose=True)
140178
# TODO: concatenate .shader files together into a top-level .shader for each world/ folder
179+
# TODO: generate shadertags .xml for easier navigation

0 commit comments

Comments
 (0)