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 -vproject ' 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\$modelname\s+)(?P.*models(\\|\/))(?P.+)', re.IGNORECASE ) reCDTexture = re.compile( r'(?P\$(cdTexture|cdmaterials)\s+)(?P.*models(\\|\/))(?P.+)', 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.*\$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 )