diff options
Diffstat (limited to 'devtools/goldsrc_port_scripts')
| -rw-r--r-- | devtools/goldsrc_port_scripts/PySourceSafe.py | 259 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/VisitFiles.py | 83 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/WildcardSearch.py | 61 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/find_game_sounds.py | 59 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/goldsrc_qc_9way_blends.py | 87 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/port_models.py | 226 | ||||
| -rw-r--r-- | devtools/goldsrc_port_scripts/qc_origin_fix.py | 35 |
7 files changed, 810 insertions, 0 deletions
diff --git a/devtools/goldsrc_port_scripts/PySourceSafe.py b/devtools/goldsrc_port_scripts/PySourceSafe.py new file mode 100644 index 0000000..372e3b6 --- /dev/null +++ b/devtools/goldsrc_port_scripts/PySourceSafe.py @@ -0,0 +1,259 @@ + + +import os, sys + + +class PySSException: + pass + + +g_bVerbose = 0 + + +class PySourceSafe: + """ + PySourceSafe represents a connection to a SS database. + Pass the directory to the database in the constructor, or \\hl2vss\hl2vss is assumed. + """ + + def __init__( self, dbPath=r"\\hl2vss\hl2vss" ): + # Store this off so we can put it in the environment when we run ss. + self.m_DBPath = dbPath + self.bUseExceptions = 0 + + self.m_VSSCommand = None + + # Since we can't use spawnvpe to have it find ss.exe for us, we have to look in the path for it manually. + paths = os.environ['path'].split( ';' ) + for path in paths: + if path[-1:] == '/' or path[-1:] == '\\': + testFilename = path + 'ss.exe' + else: + testFilename = path + '\\' + 'ss.exe' + + testFilename = testFilename.replace( '\"', '' ) + if os.access( testFilename, os.F_OK ): + self.m_VSSCommand = testFilename + break + + # If we can't find the vss command, they we're screwed so throw an exception. + if not self.m_VSSCommand: + raise PySSException + + for_cmd = 'for %I in ("' + self.m_VSSCommand + '") do echo %~sI' + p = os.popen(for_cmd) + self.m_VSSCommand = p.readlines()[-1] # last line from for command + p.close() + + self.m_VSSCommand = self.m_VSSCommand.replace( '\n', '' ) + self.lastExitStatus = 0 + self.m_LastCommandOutput = '' + + + # Throw an exception on error? Default is no. + def EnableExceptions( self, bEnable ): + self.bUseExceptions = 1 + + + # Get the output from the last command. + # This returns a list of the lines of text with the output. + def GetLastCommandOutput(): + return self.m_LastCommandOutput + + + # Return a list of the filenames in a directory. + def ListFiles( self, rootDir ): + outlines = self.__RunCommand( ['dir',rootDir] ) + if not outlines: + return None + + returnList = [] + for i in range( 1, len( outlines ) ): + if len( outlines[i] ) == 0: + break + elif outlines[i][0:1] != '$': + returnList.append( outlines[i] ) + + return returnList + + + def ListDirectories( self, rootDir ): + outlines = self.__RunCommand( ['dir',rootDir] ) + if not outlines: + return None + + returnList = [] + for i in range( 1, len( outlines ) ): + if len( outlines[i] ) == 0: + break + elif outlines[i][0:1] == '$': + returnList.append( outlines[i] ) + + return returnList + + + # Example: p.AddFile( "$/hl2/release/dev/hl2/scripts", "c:\\test.txt", "some comment here" ) + def AddFile( self, vssDir, localFilename, comment=None ): + if not self.__RunCommand( ['cp', vssDir] ): + return None + + args = ['add', localFilename, '-I-'] + if comment: + args.append( '-C%s' % comment ) + + return self.__RunCommand( args ) + + + # Create a new directory (or 'subproject'). + # Example: p.CreateDirectory( '$/tfc/models/test' ) + # Note: this WILL create the subdirectories leading up to the final one if they don't exist. + def CreateDirectory( self, vssDir, comment=None ): + if not comment: + comment = '' + + lastRet = [] + + # Create all directories leading up to this one/ + dirs = vssDir.split( '/' ) + curDir = '' + for dir in dirs: + if len( curDir ) == 0: + curDir = dir + else: + curDir = curDir + '/' + dir + + # Does it exist already? + self.__RunCommand( ['properties', curDir], 0 ) + if self.lastExitStatus != 0 and self.lastExitStatus != None: + lastRet = self.__RunCommand( ['create', curDir, '-C%s' % comment, '-I-'] ) + if lastRet == None: + break + + return lastRet + + + # Remove a file. Returns: + # 0 if the file doesn't exist + # 1 if it existed and was removed + # None if the file existed but there was an error. + def DeleteFile( self, vssFilename ): + self.__RunCommand( ['properties', vssFilename], 0 ) + if self.lastExitStatus: + return 0 + else: + # Now try to remove it. + self.__RunCommand( ['delete', vssFilename, '-I-'] ) + if self.lastExitStatus: + return None + else: + return 1 + + + # Get the checkout status of a file (and find out if the file even exists). + def GetFileStatus( self, ssFilename ): + pass + + + # Get the local working directory for the specified SS directory. + def GetWorkingDirectory( self, ssDir ): + pass + + + # Get the local filename for the specified file. + def GetLocalFilename( self, ssFilename ): + pass + + + # For all the CheckOut and Get commands, if localFilename is not None, then it'll + # treat that as the local file. Otherwise, it'll use the default working directory for that directory in SS. + # Returns 1 if successful, 0 if there was an error. + + # Check out a file. + # Use GetLastOutput() to get the output string. + def CheckOutFile( self, ssFilename, localFilename=None ): + pass + + + # Check out the whole directory. + def CheckOutDir( self, ssDirName, localDirName=None, bRecursive=0 ): + pass + + + # Get a file. + def GetFile( self, ssFilename, localFilename=None ): + pass + + + # Get a whole directory. + def GetFile( self, ssFilename, localFilename=None ): + pass + + # Check in a file. Optionally specify a comment. + # Returns 1 if successful, 0 otherwise. + def CheckInFile( self, ssFilename, localFilename=None, comment=None ): + pass + + + # The big master function to run a vss command and get the results back in a list. + def __RunCommand( self, args, bHandleErrors=1 ): + # First, set the environment up. + tempEnviron = os.environ + os.environ['ssdir'] = self.m_DBPath + + # Now build the command. + cmd = self.m_VSSCommand + for i in args: + cmd = cmd + ' \"%s\"' % i + + if g_bVerbose: + print "VSS: " + cmd + + # Run the command and capture its output. + f = os.popen( cmd, 'r' ) + lines = f.readlines() + self.lastExitStatus = f.close() + + self.m_LastCommandOutput = lines + lines = [i.strip() for i in lines] + + # Restore the environment. + os.environ = tempEnviron + + if self.lastExitStatus != 0 and self.lastExitStatus != None: + if bHandleErrors: + print 'VSS Error (status: %d): ' % self.lastExitStatus + print 'cmd: %s' % cmd + print 'output: ' + for i in lines: + print '\t%s' % i + + if self.bUseExceptions: + raise PySSException + else: + return None + + return lines + + + +p = PySourceSafe() + + +# TEST CODE +""" +print "Files" +files = p.ListFiles( '$/hl2/release/dev' ) +for i in files: + print i + +print "\n\nDirectories" +files = p.ListDirectories( '$/hl2/release/dev' ) +for i in files: + print i + + +vssRoot = '$/tfc/models' +p.AddFile( "$/tfc", "c:\\test.txt", "test comment blah blah" ) + +p.CreateDirectory( '$/tfc/aa/bb/cc/dd', 'here is hte comment' ) +""" diff --git a/devtools/goldsrc_port_scripts/VisitFiles.py b/devtools/goldsrc_port_scripts/VisitFiles.py new file mode 100644 index 0000000..50105c1 --- /dev/null +++ b/devtools/goldsrc_port_scripts/VisitFiles.py @@ -0,0 +1,83 @@ + +import os +import re + + +STOP_RECURSING = 23452 + + +class VisitFiles: + """ + This is a helper class to visit a bunch of files in a tree given + the regular expressions that will match the filenames you're interested in. + + Create this class like a function, and pass in these parameters: + baseDir - a string for the root directory in the search. This must not end in a slash. + + fileMasks - a list of strings that contain regular expressions for filenames you want to match. + + fileCB - This function is called for each filename matched. It takes these parameters: + - short filename ("blah.txt") + - relative filename ("a/b/c/blah.txt") + - long filename ("c:/basedir/a/b/c/blah.txt") + + dirCB - a function called for each directory name. This can be None. If it returns STOP_RECURSING, + then it won't do callbacks for the files and directories under this one. + - relative dirName ("./a/b") + - full dirname (from the baseDir you pass into __init__) ("d:/a/b") + + bRecurse - a boolean telling whether or not to recurse into other directories. + + Example: This would visit all files recursively (.+ matches any non-zero-length string). + VisitFiles( ".", [".+"], MyCallback ) + """ + + def __init__( self, baseDir, fileMasks, fileCB, dirCB, bRecurse=1 ): + # Handle it appropriately whether they pass 1 filemask or a list of them. + if isinstance( fileMasks, list ): + self.fileMasks = [re.compile( x, re.IGNORECASE ) for x in fileMasks] + else: + self.fileMasks = [re.compile( fileMasks, re.IGNORECASE )] + + self.fileCB = fileCB + self.dirCB = dirCB + self.bRecurse = bRecurse + + self.__VisitFiles_R( ".", baseDir ) + + + def __RemoveDotSlash( self, name ): + if name[0:2] == '.\\': + return name[2:] + else: + return name + + + def __VisitFiles_R( self, relativeDirName, baseDirName ): + if self.dirCB: + if self.dirCB( relativeDirName, baseDirName ) == 0: + return + + files = os.listdir( baseDirName ) + + for filename in files: + upperFilename = filename.upper() + fullFilename = self.__RemoveDotSlash( baseDirName + "\\" + filename ) + relativeName = self.__RemoveDotSlash( relativeDirName + "\\" + filename ) + + stats = os.stat( fullFilename ) + if stats[0] & (1<<15): + + matched = 0 + for curRE in self.fileMasks: + if curRE.search( upperFilename ): + matched = 1 + break + + if matched: + self.fileCB( filename, relativeName, fullFilename ) + else: + + # It's a directory. + if self.bRecurse: + self.__VisitFiles_R( relativeName, fullFilename ) diff --git a/devtools/goldsrc_port_scripts/WildcardSearch.py b/devtools/goldsrc_port_scripts/WildcardSearch.py new file mode 100644 index 0000000..954a092 --- /dev/null +++ b/devtools/goldsrc_port_scripts/WildcardSearch.py @@ -0,0 +1,61 @@ + +from __future__ import generators +import os +import re +import stat + + +# This takes a DOS filename wildcard like *abc.t?t and returns a regex string that will match it. +def GetRegExForDOSWildcard( wildcard ): + # First find the base directory name. + iLast = wildcard.rfind( "/" ) + if iLast == -1: + iLast = wildcard.rfind( "\\" ) + + if iLast == -1: + dirName = "." + dosStyleWildcard = wildcard + else: + dirName = wildcard[0:iLast] + dosStyleWildcard = wildcard[iLast+1:] + + # Now generate a regular expression for the search. + # DOS -> RE + # * -> .* + # . -> \. + # ? -> . + reString = dosStyleWildcard.replace( ".", r"\." ).replace( "*", ".*" ).replace( "?", "." ) + r'\Z' + return reString + + +# +# Useful function to return a list of files in a directory based on a dos-style wildcard like "*.txt" +# +# for name in WildcardSearch( "d:/hl2/src4/dt*.cpp", 1 ): +# print name +# +def WildcardSearch( wildcard, bRecurse=0 ): + reString = GetRegExForDOSWildcard( wildcard ) + matcher = re.compile( reString, re.IGNORECASE ) + + return __GetFiles_R( matcher, dirName, bRecurse ) + +def __GetFiles_R( matcher, dirName, bRecurse ): + fileList = [] + # For each file, see if we can find the regular expression. + files = os.listdir( dirName ) + for baseName in files: + filename = dirName + "/" + baseName + + mode = os.stat( filename )[stat.ST_MODE] + if stat.S_ISREG( mode ): + # Make sure the file matches the search string. + if matcher.match( baseName ): + fileList.append( filename ) + + elif bRecurse and stat.S_ISDIR( mode ): + fileList += __GetFiles_R( matcher, filename, bRecurse ) + + return fileList + + diff --git a/devtools/goldsrc_port_scripts/find_game_sounds.py b/devtools/goldsrc_port_scripts/find_game_sounds.py new file mode 100644 index 0000000..7b0a955 --- /dev/null +++ b/devtools/goldsrc_port_scripts/find_game_sounds.py @@ -0,0 +1,59 @@ + +import os +import sys +import stat + + +g_NumSoundsAdded = 0 + + +def ScanSounds_R( baseDir, relativeDir, outFile ): + files = os.listdir( baseDir ) + for filename in files: + fullFilename = baseDir + "\\" + filename + if len( relativeDir ) > 0: + newRelativeDir = relativeDir + "/" + filename + else: + newRelativeDir = filename + + mode = os.stat( fullFilename )[stat.ST_MODE] + + if stat.S_ISREG( mode ): + if filename[-4:].upper() == ".WAV": + outFile.write( "\"%s\"\n" % ( newRelativeDir[0:-4] ) ) + outFile.write( "{\n" ) + outFile.write( "\t\"channel\"\t\t\"CHAN_ITEM\"\n" ) + outFile.write( "\t\"volume\"\t\t\"VOL_NORM\"\n" ) + outFile.write( "\t\"soundlevel\"\t\"SNDLVL_NONE\"\n" ) + outFile.write( "\t\"pitch\"\t\t\t\"PITCH_NORM\"\n" ) + outFile.write( "\t\"wave\"\t\t\t\"%s\"\n" % ( newRelativeDir ) ) + outFile.write( "}\n\n" ) + + global g_NumSoundsAdded + g_NumSoundsAdded += 1 + + if stat.S_ISDIR( mode ): + ScanSounds_R( fullFilename, newRelativeDir, outFile ) + + +# Make sure we've got a valid base directory. +if len( sys.argv ) < 2: + print "Error: Must specify the root sound directory." + sys.exit( 1 ) + +baseDir = sys.argv[1] +if os.access( baseDir, os.R_OK ) != 1: + print "Error: Can't access %s." % ( baseDir ) + sys.exit( 1 ) + + +# Now scan all the .cpp files for sound function calls. +outFile = open( "game_sounds.txt", "wt" ) + +ScanSounds_R( baseDir, "", outFile ) + +outFile.close() + + +print "Added %d sounds to game_sounds.txt" % ( g_NumSoundsAdded ) + diff --git a/devtools/goldsrc_port_scripts/goldsrc_qc_9way_blends.py b/devtools/goldsrc_port_scripts/goldsrc_qc_9way_blends.py new file mode 100644 index 0000000..19869d9 --- /dev/null +++ b/devtools/goldsrc_port_scripts/goldsrc_qc_9way_blends.py @@ -0,0 +1,87 @@ + +# This script converts old 9 way blends that look like this: +# +# $sequence crouch_tommy_shoot "crouch_tommy_shootupL" "crouch_tommy_shootup" "crouch_tommy_shootupR" "crouch_tommy_shootmidL" "crouch_tommy_shootmid" "crouch_tommy_shootmidR" "crouch_tommy_shootdownL" "crouch_tommy_shootdown" "crouch_tommy_shootdownL" blend XR 45 -45 fps 30 origin 0 0 17 { event 7002 1 "1" } +# +# to this: +# +# $sequence crouch_tommy_shoot { +# "crouch_tommy_shootupL" "crouch_tommy_shootup" "crouch_tommy_shootupR" +# "crouch_tommy_shootmidL" "crouch_tommy_shootmid" "crouch_tommy_shootmidR" +# "crouch_tommy_shootdownL" "crouch_tommy_shootdown" "crouch_tommy_shootdownL" +# blendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65 +# fps 30 origin 0 0 17 { event 7002 1 "1" } +# } + +import sys +import re +import string + +if len( sys.argv ) < 3: + print "Requires 2 parameters: <input file> <output file>" + sys.exit( 1 ) + + +# Read in the file. +f = open( sys.argv[1], "rt" ) +lines = f.readlines() +f.close() + + +# Do the search/replace. +def named( re, name ): + return r'(?P<' + name + r'>' + re + ')' + +def ident( animName ): + if animName: + return named( r'\"?\S+\"?', animName ) + else: + return r'\"?\S+\"?' + + +ws = r'\s*' + +# THIS IS THE FIRST PASS - ADDS THE 9-WAY BLENDS +if 1: + nineNames = [ws+ident('a'+str(i)) for i in range(1,10)] + sequenceAndAnims = named( r'\s*', 'prefix' ) + r'\$sequence' + ws + ident('animName') + string.join( nineNames, '' ) + + # NOTE THERE IS A KNOWN BUG HERE - extra NEEDS TO INCLUDE THE 'blend xr -45 45' STUFF SO WE CAN STRIP IT OUT + extra = ws + ident('blend') + named( '.+', 'extra' ) + myRE = re.compile( sequenceAndAnims + extra ) + + #lines = ['$sequence crouch_pistol_aim "crouch_pistol_aimupL" "crouch_pistol_aimup" "crouch_pistol_aimupR" "crouch_pistol_aimmidL" "crouch_pistol_aimmid" "crouch_pistol_aimmidR" "crouch_pistol_aimdownL" "crouch_pistol_aimdown" "crouch_pistol_aimdownR" loop blend XR 45 -45 fps 30 origin 0 0 17'] + + outLines = [] + for curLine in lines: + m = myRE.match( curLine ) + if m and (m.group('blend') == 'blend' or m.group('blend') == 'loop'): + prefix = m.group('prefix') + curLine = prefix + '$sequence %s {\n' % m.group('animName') + curLine += prefix + '\t%s %s %s\n' % ( m.group('a1'), m.group('a2'), m.group('a3') ) + curLine += prefix + '\t%s %s %s\n' % ( m.group('a4'), m.group('a5'), m.group('a6') ) + curLine += prefix + '\t%s %s %s\n' % ( m.group('a7'), m.group('a8'), m.group('a9') ) + curLine += prefix + '\tblendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65\n' + curLine += prefix + '\t' + m.group( 'extra' ) + '\n' + curLine += prefix + '}\n\n' + + outLines.append( curLine ) + +# THIS IS THE SECOND PASS - IT ADDS THE UPPER-BODY WEIGHTLISTS +if 0: + lookFor = named( r'\s*', 'start' ) + named( r'blendwidth 3 blend body_yaw -45 45 blend body_pitch -65 65', 'mid' ) + named( r'\s*', 'end' ) + myRE = re.compile( lookFor ) + + outLines = [] + for curLine in lines: + m = myRE.match( curLine ) + if m: + curLine = curLine + m.group('start') + 'weightlist upperbody\n' + + outLines.append( curLine ) + + +# Save the output file. +f = open( sys.argv[2], "wt" ) +f.writelines( outLines ) +f.close() diff --git a/devtools/goldsrc_port_scripts/port_models.py b/devtools/goldsrc_port_scripts/port_models.py new file mode 100644 index 0000000..bd5fcc1 --- /dev/null +++ b/devtools/goldsrc_port_scripts/port_models.py @@ -0,0 +1,226 @@ + +import msvcrt, os, sys, re, WildcardSearch, VisitFiles + + +def GetArg( argName, ifAtEnd='' ): + for i in range( 1, len( sys.argv ) ): + if argName.upper() == sys.argv[i].upper(): + if i+1 >= len( sys.argv ): + return ifAtEnd + else: + return sys.argv[i+1] + return None + + +def PrintUsage(): + print r'port_models.py -srcdir <directory with the QCs> -vproject <game directory>' + print r'Note: -srcdir represents the ROOT of the models directory, but it points at the model sources' + print r' instead of the model content.' + print r'ex: port_models.py -srcdir c:\hl2\models\tfc -vproject c:\hl2\tfc' + sys.exit( 1 ) + + +def FixFilename( filename ): + filename = filename.replace( '/', '\\' ) + if filename == '.\\': + return filename + else: + return re.compile( r'[^\.]?\.\\' ).sub( '', filename ) + + +def GetDirName( fullFilename ): + a = fullFilename.rfind( '/' ) + b = fullFilename.rfind( '\\' ) + if a == -1 and b == -1: + return FixFilename( fullFilename ) + else: + return FixFilename( fullFilename[0 : max(a,b)] ) + + +g_bAlwaysContinue = 0 +def CheckContinue(): + global g_bAlwaysContinue + if g_bAlwaysContinue: + return 1 + else: + sys.stdout.write( 'Continue [(Y)es/(N)o/(A)lways]? ' ) + r = str( msvcrt.getch() ).upper() + if r == 'Y': + return 1 + elif r == 'A': + g_bAlwaysContinue = 1 + return 1 + else: + return 0 + + +# +# Get command line args. +# +modelSourceDir = GetArg( '-srcdir' ) +vprojectDir = GetArg( '-vproject' ) +if not modelSourceDir or not vprojectDir: + PrintUsage() + +binDir = vprojectDir + '\\..\\bin' + +studiomdlFilename = binDir + '\\studiomdl.exe' +vtexFilename = binDir + '\\vtex.exe' +xwadFilename = binDir + '\\xwad.exe' +if not os.access( studiomdlFilename, os.F_OK ) or not os.access( vtexFilename, os.F_OK ) or not os.access( xwadFilename, os.F_OK ): + print 'Can\'t find vtex.exe, xwad.exe, or studiomdl.exe in bin directory %s.' % (binDir) + sys.exit( 1 ) + + + +# +# +# REGEX's and code to convert the QC file. +# +# +reModelName = re.compile( r'(?P<start>\$modelname\s+)(?P<stripout>.*models(\\|\/))(?P<keep>.+)', re.IGNORECASE ) +reCDTexture = re.compile( r'(?P<start>\$(cdTexture|cdmaterials)\s+)(?P<stripout>.*models(\\|\/))(?P<keep>.+)', re.IGNORECASE ) +reCD = re.compile( r'\$cd\s', re.IGNORECASE ) + +def ident( name=None ): + if name: + return r'(?P<' + name + r'>\s+((\".*?\")|([^\"]\S*)))' + else: + return r'\s+((\".*?\")|([^\"]\S*))' + +reAttachmentLine = re.compile( r'(?P<keep>.*\$attachment'+ident()+ident()+ident()+ident()+ident() + ')' + ident()+ident(), re.IGNORECASE ) + +g_DirToMaterialsMap = {} + +def EditQCFile( fullFilename ): + f = open( fullFilename, 'rt' ) + lines = f.readlines() + f.close() + + bDidMaterials = 0 + + outLines = [] + for line in lines: + if not reCD.search( line ): + # Strip out stuff before /models in the $modelname line. + m = reModelName.search( line ) + if m: + line = m.group('start') + m.group('keep' ) + '\n' + else: + m = reCDTexture.search( line ) + if m: + materialsDirName = 'models/' + m.group('keep') + bmpDir = m.group('keep') + g_DirToMaterialsMap[FixFilename(bmpDir.upper())] = materialsDirName + bDidMaterials = 1 + line = '$cdmaterials %s\n' % materialsDirName + + # Strip out the last 2 args on the $attachment line if they're using too many. + # Goldsrc studiomdl allowed 2 extra args but it ignored them. + m = reAttachmentLine.search( line ) + if m: + line = m.group('keep') + + outLines.append( line ) + + if not bDidMaterials: + print 'No $cdtexture line in %s so we don\'t know where to convert the BMPs into.' % (fullFilename) + sys.exit( 1 ) + + # + # Write the QC back out. + # + try: + f = open( fullFilename, 'wt' ) + except IOError: + print 'Can\'t open %s for writing.\nMake sure it is not read-only.' % fullFilename + sys.exit( 1 ) + f.writelines( outLines ) + f.close() + + + +# +# Convert all the QC files and backup the old ones. +# +print '--- Converting QC files and running studiomdl ---' + +def QCFileCallback( filename, relativeName, fullFilename ): + print '\t' + relativeName + + # First, backup the QC. + os.system( 'copy \"%s\" \"%s\" > out' % (fullFilename, fullFilename + ".OLD") ) + + # + # Now, make some edits. + # + EditQCFile( fullFilename ); + + # + # Run studiomdl on it. + # + cmd = '%s -vproject \"%s\" \"%s\" > out' % (studiomdlFilename, vprojectDir, fullFilename) + if os.system( cmd ) != 0: + lines = open( 'out', 'rt' ).readlines() + sys.stdout.writelines( lines ) + sys.exit( 1 ) + +VisitFiles.VisitFiles( modelSourceDir, WildcardSearch.GetRegExForDOSWildcard( '*.qc' ), QCFileCallback, None ) + + +# +# Now convert all the BMP files. +# +print '\n--- Converting BMP files and running vtex ---' +def BMPFileCallback( filename, relativeName, fullFilename ): + print '\t' + relativeName + + # Find out where we want to store this BMP's files under materials. + dirName = GetDirName( relativeName ) + + try: + cdMaterials = g_DirToMaterialsMap[dirName.upper()] + except: + #print '\tWarning: couldn\'t convert %s (don\'t know where to put it).' % (relativeName) + pass + else: + # + # Run XWAD. + # + cmd = '%s -quiet -bmpfile \"%s\" -basedir \"%s\"' % (xwadFilename, fullFilename, vprojectDir) + if os.system( cmd ) != 0: + print '\tError running xwad on %s' % fullFilename + if not CheckContinue(): + print '\tcmd: %s' % cmd + sys.exit( 1 ) + + # + # Move the TGA it generated into the right directory. + # + materialsrcDir = '%s\\materialsrc\\%s' % (vprojectDir, cdMaterials) + if not os.access( materialsrcDir, os.F_OK ) and os.system( 'md \"%s\"' % materialsrcDir ) != 0: + print 'Can\'t create or access directory %s.' % materialsrcDir + + materialsDir = '%s\\materials\\%s' % (vprojectDir, cdMaterials) + if not os.access( materialsDir, os.F_OK ) and os.system( 'md \"%s\"' % materialsDir ) != 0: + print 'Can\'t create or access directory %s.' % materialsDir + + baseTGAFilename = filename[0:-4] + '.tga' + generatedFilename = vprojectDir + '\\materialsrc\\' + baseTGAFilename + cmd = 'move \"%s\" \"%s\"' % (generatedFilename, materialsrcDir) + if os.system( cmd ) != 0: + print 'system( %s ) failed.' % cmd + + # + # Lastly, run vtex on it. + # + cmd = '%s -shader VertexLitGeneric -quiet \"%s\\%s\"' % (vtexFilename, materialsrcDir, baseTGAFilename) + if os.system( cmd ) != 0: + sys.exit( 1 ) + + +VisitFiles.VisitFiles( modelSourceDir, WildcardSearch.GetRegExForDOSWildcard( '*.bmp' ), BMPFileCallback, None ) + + + + diff --git a/devtools/goldsrc_port_scripts/qc_origin_fix.py b/devtools/goldsrc_port_scripts/qc_origin_fix.py new file mode 100644 index 0000000..63541db --- /dev/null +++ b/devtools/goldsrc_port_scripts/qc_origin_fix.py @@ -0,0 +1,35 @@ + +# +# This script is used to take a goldsrc-style character model with the origin at +# its centerpoint and put its origin at its feet. +# +# It parses a .qc file, takes all $origin commands, and subtracts that amount +# from all 'origin' blocks inside a sequence command. +# +# Redirect its output to a file (or the input file). +# + +import sys +import re + +f = open( sys.argv[1], "rt" ) +lines = f.readlines() +f.close() + +re1 = re.compile( r'\$origin (?P<x>-?\d+)\s+(?P<y>-?\d+)\s+(?P<z>-?\d+)' ) +re2 = re.compile( r'(?P<ws>\s)origin (?P<x>-?\d+)\s+(?P<y>-?\d+)\s+(?P<z>-?\d+)' ) + +curOffset = [0,0,0] + +def OriginOffset( m ): + testOffset = [ int(m.group('x')), int(m.group('y')), int(m.group('z')) ] + return '%sorigin %d %d %d' % (m.group('ws'), testOffset[0]-curOffset[0], testOffset[1]-curOffset[1], testOffset[2]-curOffset[2]) + +for line in lines: + m = re1.search( line ) + if m: + #print 'match: %s %s %s' % ( m.group('x'), m.group('y'), m.group('z') ) + curOffset = [ int(m.group('x')), int(m.group('y')), int(m.group('z')) ] + + sys.stdout.write( re2.sub( OriginOffset, line ) ) + |