6
6
#
7
7
# You should have received a copy of the license along with this
8
8
# work. If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.
9
- """generate .vmt files from a folder of .vtf files (from a template .vmt) """
9
+ """generate .vmt files from a folder of .vtf files"""
10
10
from __future__ import annotations
11
11
import argparse
12
12
import fnmatch
15
15
from typing import Dict , List , Tuple
16
16
17
17
from colour import Color
18
- from gooey import Gooey
18
+ # from gooey import Gooey
19
19
20
- import vtf
20
+ # import VTFLibWrapper
21
21
22
22
23
23
__version__ = "1.0.0"
24
24
25
25
26
- def from_template (template : str , vtf_filename : str , ** substitutions : Dict [str , str ]):
26
+ def from_template (vtf_filename : str , template : str , ** substitutions : Dict [str , str ]):
27
27
"""Generate .vmts from `template` for every .vtf in `folder`"""
28
28
# example usage:
29
29
# from_template("LightmappedGeneric{$basetexture <filename>}", "materials/folder")
@@ -34,30 +34,31 @@ def from_template(template: str, vtf_filename: str, **substitutions: Dict[str, s
34
34
# '$basetexture2 <texture2>' --> '"$blendmodulatetexture" "<filename>_bm"'
35
35
# then at the file level: '<filename>_bm' -> 'texture_bm' for "texture.vmt"
36
36
# NOTE: never put filename in replacements unless you want to replace all textures with one texture!
37
- filename = os .splitext (vtf_filename ) # remove .vtf extension
37
+ filename = os .path . splitext (vtf_filename )[ 0 ] # remove .vtf extension
38
38
with open (f"{ filename } .vmt" , "w" ) as vmt_file :
39
39
vmt_file .write (template .replace ("<filename>" , filename ))
40
40
41
41
42
42
# TODO: maybe separate file filtering from .vmt writing?
43
43
def from_metadata (vtf_filename : str , shader : str = "LightmappedGeneric" , ** flags : Dict [str , Tuple [str , str ]]):
44
- """filename shouldn't have an extension """
44
+ """generate an appropriate .vmt from .vmt flags """
45
45
raise NotImplementedError ()
46
46
# * EXPECTED FLAGS *
47
47
# has_alpha: bool // vtf is transparent e.g. {"has_alpha": "$translucent": 1}
48
48
# colour: Color // fuzzy colour detection
49
49
# hue_range: float // [0-1]; how close the texture's hue should be to colour
50
50
51
- filename = os .path .splitext (vtf_filename )
52
- vtf_header = vtf .Vtf .from_file (f"{ filename } .vtf" ).header
51
+ filename = os .path .splitext (vtf_filename )[0 ]
52
+
53
+ vtf = ... # TODO: load f"{filename}.vtf" with VTFLibWrapper
53
54
# check flags
54
55
if "color" in flags :
55
56
flags ["colour" ] = flags .pop ("color" )
56
57
if "transparent" in flags :
57
58
flags ["has_alpha" ] = flags .pop ("transparent" )
58
59
checks : Dict [str , bool ]
59
- checks = {"colour" : fuzzy_colour_match (vtf_header .reflectivity , flags ["colour" ], flags .get ("hue_range" , 0 )),
60
- "has_alpha" : vtf_header . image_format in vtf . transparent_formats ,
60
+ checks = {"colour" : fuzzy_colour_match (vtf .reflectivity , flags ["colour" ], flags .get ("hue_range" , 0 )),
61
+ "has_alpha" : has_alpha ( vtf ) ,
61
62
None : None }
62
63
# ^ {"flag": True or False}
63
64
metadata = {f : checks .get (f , None ) for f in flags }
@@ -79,12 +80,17 @@ def fuzzy_colour_match(a: Color, b: Color, hue_range: float) -> bool:
79
80
return abs (a .hsl [0 ] - b .hsl [0 ]) <= hue_range
80
81
81
82
82
- def process_folder (method : str , folders : List [str ], ignore = [], recursive = False , verbose = False , ** kwargs ):
83
+ def has_alpha (vtf ) -> bool :
84
+ raise NotImplementedError ()
85
+ return vtf .image_format in (...)
86
+
87
+
88
+ def parse_folder (method : str , folders : List [str ], template = None , ignore = [], recursive = False , verbose = False , ** kwargs ):
83
89
# pre-processing
84
90
ignore_patterns = [re .compile (p ) for p in ignore ]
85
91
if method == "template" :
86
92
# kwargs["substutions"]: Dict[str, str] = {"keyword": "replacement"}
87
- template = open (kwargs . pop ( " template" ) ).read ()
93
+ template = open (template ).read ()
88
94
# NOTE: the "template" kwarg must be supplied! [process_folder(..., template="base.vmt")]
89
95
# template substitutions
90
96
for keyword , replacement in kwargs .pop ("substitutions" , dict ()).items ():
@@ -98,11 +104,11 @@ def process_folder(method: str, folders: List[str], ignore=[], recursive=False,
98
104
99
105
# parse all folders
100
106
for folder in folders :
107
+ folder_contents = [os .path .join (f ) for f in os .listdir (folder )]
101
108
if recursive :
102
- folder_contents = [os .path .join (f ) for f in os .listdir (folder )]
103
109
folders .extend ([d for d in folder_contents if os .path .isdir (d )])
104
110
for vtf_filename in fnmatch .filter (folder_contents , "*.vtf" ):
105
- filename = os .path .join (folder , os .path .splitext (vtf_filename ))
111
+ filename = os .path .join (folder , os .path .splitext (vtf_filename )[ 0 ] )
106
112
if any ([pattern .match (filename ) for pattern in ignore_patterns ]):
107
113
if verbose :
108
114
print ("Skipping {filename}.vmt" )
@@ -111,14 +117,15 @@ def process_folder(method: str, folders: List[str], ignore=[], recursive=False,
111
117
if verbose :
112
118
print (f"Writing { filename } .vmt... " , end = "" )
113
119
if method == "template" :
114
- from_template (vtf_filename , template )
120
+ from_template (filename , template )
115
121
elif method == "metadata" :
116
- from_metadata (vtf_filename , ** kwargs )
122
+ # TODO: do a keyword substitution pass on flags.values
123
+ from_metadata (filename , ** kwargs )
117
124
if verbose :
118
125
print ("Done!" )
119
126
120
127
121
- @Gooey
128
+ # @Gooey
122
129
def main (with_args : List [str ] = None ):
123
130
notes = ["You can drag any folder over %(prog)s and just use the defaults" ,
124
131
"--template (default: base.vmt next to %(prog)s) must have a <filename> keyword!" ,
@@ -134,15 +141,17 @@ def main(with_args: List[str] = None):
134
141
mode = parser .add_mutually_exclusive_group ()
135
142
mode .add_argument ("-t" , "--template" , default = "base.vmt" ,
136
143
help = "generate vmts from the supplied template\n default: base.vmt" )
137
- mode .add_argument ("-m" , "--metadata" , action = "store_true" )
144
+ mode .add_argument ("-m" , "--metadata" , action = "store_true" ,
145
+ help = "generate each .vmt based on flags set in the .vtf\n NOT IMPLEMENTED YET" )
138
146
parser .add_argument ("-f" , "--flags" ,
139
- help = "colon separated metadata flags\n (e.g. has_alpha:$translucent:1)" )
147
+ help = "colon separated metadata flags\n (e.g. has_alpha:$translucent:1)\n NOT IMPLEMENTED YET" )
148
+ # TODO: set vmt shader (default: LightmappedGeneric)
140
149
# TODO: list all available flags
141
- parser .add_argument ("-s" , "--substitute" , action = "append" , metavar = "KEYWORD:REPLACEMENT " , dest = "subs" ,
142
- help = "substitute <KEYWORD > in template with REPLACEMENT \n (e.g. `bumpmap:<filename>_bump`)" )
150
+ parser .add_argument ("-s" , "--substitute" , action = "append" , metavar = "keyword:replacement " , default = [] ,
151
+ help = "substitute <keyword > in template with replacement \n (e.g. `bumpmap:<filename>_bump`)" )
143
152
parser .add_argument ("-r" , "--recurse" , action = "store_true" ,
144
- help = "generate .vmts for all folders within FOLDER " )
145
- parser .add_argument ("-i" , "--ignore" , action = "append" , metavar = "PATTERN " , nargs = "*" ,
153
+ help = "generate .vmts for all folders within folder " )
154
+ parser .add_argument ("-i" , "--ignore" , action = "append" , metavar = "patterns " , nargs = "*" , default = [] ,
146
155
help = "skip <filename> if it matches any of the given patterns" )
147
156
# TODO: --generate (metadata based .vmt & adding / removing relevant key-value pairs [no template])
148
157
# TODO: --surfaceprop choice to add a surfaceprop
@@ -157,15 +166,15 @@ def main(with_args: List[str] = None):
157
166
args = parser .parse_args ()
158
167
159
168
# if not args.metadata: # template mode
160
- replacements = {k .strip ("<>" ): v for a in args .replace for k , v in a .split (":" )}
169
+ replacements = {k .strip ("<>" ): v for a in args .substitute for k , v in a .split (":" )}
161
170
# replacements are colon separated; < & > around the keyword are optional
162
171
# setting filename will give all make all .vmts generated identical! even the basetexture!
163
- process_folder ("template" , args .template , args .folders ,
164
- ignore = args .ignore , verbose = args .verbose , substitutions = replacements )
172
+ parse_folder ("template" , args .folders , template = args .template , substitutions = replacements ,
173
+ ignore = args .ignore , verbose = args .verbose )
165
174
# else: # metadata mode
166
175
# flags = {f: (p, v) for m in args.metadata for f, p, v in m.split(":")}
167
- # process_folder("metadata", args.folders,
168
- # ignore=args.ignore, verbose=args.verbose, flags=flags )
176
+ # process_folder("metadata", args.folders, flags=flags,
177
+ # ignore=args.ignore, verbose=args.verbose)
169
178
170
179
171
180
if __name__ == "__main__" :
0 commit comments