This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
@@ -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' )
"""
@@ -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 )
@@ -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
@@ -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 )
@@ -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()
@@ -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 )
@@ -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 ) )