*** empty log message ***

This commit is contained in:
Joe Shochet 2000-11-07 21:49:37 +00:00
parent 1f4c504b42
commit 0901fd9c20
8 changed files with 244 additions and 132 deletions

View File

@ -3,10 +3,6 @@
from DirectNotifyGlobal import *
notify = directNotify.newCategory("FFI")
# This is the name of the file that the global functions and values
# will be stored
globalModuleName = 'PandaGlobals'
# This is the name of the file that the importing code will be stored
importModuleName = 'PandaModules'

View File

@ -2,8 +2,12 @@ import FFIConstants
class FFIEnvironment:
def __init__(self):
self.reset()
def reset(self):
self.types = {}
self.globalFunctions = []
self.downcastFunctions = []
self.globalValues = []
self.manifests = []
@ -20,6 +24,8 @@ class FFIEnvironment:
def addGlobalFunction(self, typeDescriptor):
self.globalFunctions.append(typeDescriptor)
def addDowncastFunction(self, typeDescriptor):
self.downcastFunctions.append(typeDescriptor)
def addGlobalValue(self, typeDescriptor):
self.globalValues.append(typeDescriptor)
def addManifest(self, typeDescriptor):

View File

@ -4,26 +4,19 @@ import TypedObject
WrapperClassMap = {}
# For testing, you can turn verbose and debug on
FFIConstants.notify.setVerbose(1)
FFIConstants.notify.setDebug(1)
def getDowncastFunctions(thisClass, baseClass, chain):
if (thisClass == baseClass):
# Found it, return true
return 1
elif (len(thisClass.__bases__) == 0):
# Not here, return 0
return 0
else:
# Look recursively in the classes thisClass inherits from
for base in thisClass.__bases__:
# If it finds it, append the base class's downcast function
# to the chain if it has one
if getDowncastFunctions(base, baseClass, chain):
downcastFuncName = 'downcastTo' + thisClass.__name__
if base.__dict__.has_key(downcastFuncName):
FFIConstants.notify.debug('Found downcast function %s in %s' % (downcastFuncName, base.__name__))
chain.append(base.__dict__[downcastFuncName])
return chain
# Register a python class in the type map if it is a typed object
# The type map is used for upcasting and downcasting through
# the panda inheritance chain
def registerInTypeMap(pythonClass):
if issubclass(pythonClass, TypedObject.TypedObject):
typeIndex = pythonClass.getClassType().getIndex()
WrapperClassMap[typeIndex] = pythonClass
class FFIExternalObject:
@ -32,23 +25,52 @@ class FFIExternalObject:
self.userManagesMemory = 0
# Start with a null this pointer
self.this = 0
def getDowncastFunctions(self, thisClass, baseClass, chain):
if (thisClass == baseClass):
# Found it, return true
return 1
elif (len(thisClass.__bases__) == 0):
# Not here, return 0
return 0
else:
# Look recursively in the classes thisClass inherits from
for base in thisClass.__bases__:
# If it finds it, append the base class's downcast function
# to the chain if it has one
if self.getDowncastFunctions(base, baseClass, chain):
downcastFuncName = ('downcastTo' + thisClass.__name__
+ 'From' + base.__name__)
# Look over this classes global modules dictionaries
# for the downcast function name
for globmod in self.__class__.__CModuleDowncasts__:
if globmod.__dict__.has_key(downcastFuncName):
func = globmod.__dict__[downcastFuncName]
FFIConstants.notify.debug('Found downcast function %s in %s'
% (downcastFuncName, globmod.__name__))
chain.append(func)
return chain
else:
FFIConstants.notify.debug('Did not find downcast function %s in %s'
% (downcastFuncName, globmod.__name__))
# In any case, return the chain
return chain
# Probably went up the wrong tree and did not find the rootClass
else:
return []
def asExactType(self):
return self.getType()
def isTypedObject(self):
return isinstance(self, TypedObject.TypedObject)
def setPointer(self):
if (self.this == 0):
# Null pointer, return None
return None
# If it is not a typed object, our work is done, just return the object
if (not self.isTypedObject()):
if (not isinstance(self, TypedObject.TypedObject)):
return self
# Ok, it is a typed object. See what type it really is and downcast
# to that type (if necessary)
exactWrapperClass = self.wrapperClassForTypeHandle(self.asExactType())
exactWrapperClass = self.wrapperClassForTypeHandle(self.getType())
# We do not need to downcast if we already have the same class
if (exactWrapperClass and (exactWrapperClass != self.__class__)):
# Create a new wrapper class instance
@ -71,16 +93,10 @@ class FFIExternalObject:
else:
return None
def registerInTypeMap(self):
global WrapperClassMap
if self.isTypedObject():
typeIndex = self.__class__.getClassType().getIndex()
WrapperClassMap[typeIndex] = self.__class__
def downcast(self, specificClass):
FFIConstants.notify.debug('downcasting from %s to %s' % \
(self.__class__.__name__, specificClass.__name__))
downcastChain = getDowncastFunctions(specificClass, self.__class__, [])
downcastChain = self.getDowncastFunctions(specificClass, self.__class__, [])
FFIConstants.notify.debug('downcast chain: ' + `downcastChain`)
newObject = self
if (downcastChain == None):
@ -124,7 +140,4 @@ class FFIExternalObject:

View File

@ -21,26 +21,30 @@ FFIConstants.notify.info('Importing interrogate library: ' + FFIConstants.Interr
# to be dependent on the name of the interrogate library in this code
exec('from ' + FFIConstants.InterrogateModuleName + ' import *')
# Import all the C++ modules
for CModuleName in FFIConstants.CodeModuleNameList:
FFIConstants.notify.info('Importing code library: ' + CModuleName)
exec('import ' + CModuleName)
def constructGlobalFile(codeDir):
def constructGlobalFile(codeDir, CModuleName):
"""
Open a file that will hold the global values and functions code
"""
file = open(os.path.join(codeDir, FFIConstants.globalModuleName + '.py'), 'w')
file = open(os.path.join(codeDir, CModuleName + 'Globals' + '.py'), 'w')
return file
def constructImportFile(codeDir):
def constructDowncastFile(codeDir, CModuleName):
"""
Open a file that will hold the global values and functions code
"""
file = open(os.path.join(codeDir, FFIConstants.importModuleName + '.py'), 'w')
file = open(os.path.join(codeDir, CModuleName + 'Downcasts' + '.py'), 'w')
return file
def outputGlobalFileImports(file, methodList):
def constructImportFile(codeDir, CModuleName):
"""
Open a file that will hold the global values and functions code
"""
file = open(os.path.join(codeDir, CModuleName + 'Modules' + '.py'), 'w')
return file
def outputGlobalFileImports(file, methodList, CModuleName):
# Print the standard header
file.write(FFIConstants.generatedHeader)
@ -48,15 +52,34 @@ def outputGlobalFileImports(file, methodList):
file.write('import types\n')
# Import the C modules
for CModuleName in FFIConstants.CodeModuleNameList:
CModuleList = []
for method in methodList:
if (not (method.typeDescriptor.moduleName in CModuleList)):
CModuleList.append(method.typeDescriptor.moduleName)
for CModuleName in CModuleList:
file.write('import ' + CModuleName + '\n')
moduleList = []
for method in methodList:
returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor()
if (not (returnType.foreignTypeName in moduleList)):
returnTypeName = returnType.foreignTypeName
if (not (returnTypeName in moduleList)):
if (returnType.__class__ == FFITypes.ClassTypeDescriptor):
moduleList.append(returnType.foreignTypeName)
moduleList.append(returnTypeName)
# Look at all the arguments
argTypes = method.typeDescriptor.argumentTypes
for argType in argTypes:
# Get the real return type (not derived)
argType = argType.typeDescriptor.recursiveTypeDescriptor()
argTypeName = argType.foreignTypeName
# Do not put our own module in the import list
# Do not put modules already in the list (like a set)
if (not (argTypeName in moduleList)):
# If this is a class (not a primitive), put it on the list
if (argType.__class__ == FFITypes.ClassTypeDescriptor):
moduleList.append(argTypeName)
for moduleName in moduleList:
file.write('import ' + moduleName + '\n')
@ -64,7 +87,7 @@ def outputGlobalFileImports(file, methodList):
file.write('\n')
def outputImportFileImports(file, typeList):
def outputImportFileImports(file, typeList, CModuleName):
"""
This is the file that we will import to get all the panda modules
"""
@ -76,10 +99,8 @@ def outputImportFileImports(file, typeList):
file.write('import ' + FFIConstants.InterrogateModuleName + '\n')
file.write('\n')
file.write('# Import the C modules\n')
for CModuleName in FFIConstants.CodeModuleNameList:
file.write('import ' + CModuleName + '\n')
file.write('\n')
file.write('# Import the C module\n')
file.write('import ' + CModuleName + '\n')
# Filter out only the class and enum type descriptors (not const, pointers, etc)
classTypeList = []
@ -96,12 +117,9 @@ def outputImportFileImports(file, typeList):
classTypeList.sort(FFIOverload.inheritanceLevelSort)
moduleList = []
for type in classTypeList:
for type in classTypeList:
moduleList.append(type.foreignTypeName)
file.write('import FFIExternalObject\n')
file.write('\n')
file.write('# Import enums into the global name space\n')
for type in enumTypeList:
file.write('from ' + type.enumName + ' import *\n')
@ -113,25 +131,28 @@ def outputImportFileImports(file, typeList):
file.write('\n')
file.write('# Import the global module file into our name space\n')
file.write('from ' + FFIConstants.globalModuleName + ' import *\n')
file.write('from ' + CModuleName + 'Globals' + ' import *\n')
file.write('\n')
file.write('# Now generate the classes\n')
file.write('# Generate the classes\n')
for moduleName in moduleList:
file.write(moduleName + '.generateClass_' + moduleName + '()\n')
file.write('\n')
file.write('# Now put the classes in the wrapper class map\n')
for moduleName in moduleList:
file.write('obj = ' + moduleName + '.' + moduleName + '(None)\n')
file.write('obj.registerInTypeMap()\n')
file.write('\n')
file.write('# Now copy the classes into our own namespace\n')
file.write('# Copy the classes into our own namespace\n')
for moduleName in moduleList:
file.write(moduleName + ' = ' + moduleName + '.' + moduleName + '\n')
file.write('\n')
file.write('# Put the classes in the wrapper class map\n')
file.write('from FFIExternalObject import registerInTypeMap\n')
file.write('\n')
for moduleName in moduleList:
file.write('registerInTypeMap(' + moduleName + ')\n')
file.write('\n')
def generateStaticClass(codeDir):
"""
Create a file that will hold the static class definition
@ -472,6 +493,10 @@ class FFIInterrogateDatabase:
built into the class they are being downcast from. For instance, a method
downcastToNode(ptrBoundedObject) will appear in Node's list of methods
but should be compiled into BoundedObject's class
UPDATE: These are no longer compiled into the from-class. That was
preventing the libraries from being independent since the from class
now had knowledge of the to class which is potentially in a library
downstream. Now these functions are just global functions
"""
numFuncs = interrogate_type_number_of_derivations(typeIndex)
for i in range(numFuncs):
@ -481,15 +506,21 @@ class FFIInterrogateDatabase:
funcIndex = interrogate_type_get_downcast(typeIndex, i)
typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
for typeDesc in typeDescs:
funcSpec = FFISpecs.MethodSpecification()
funcSpec = FFISpecs.GlobalFunctionSpecification()
funcSpec.name = FFIRename.methodNameFromCppName(
interrogate_function_name(funcIndex))
funcSpec.typeDescriptor = typeDesc
funcSpec.index = funcIndex
# Here we look for the class in the first argument
fromClass = typeDesc.argumentTypes[0].typeDescriptor.recursiveTypeDescriptor()
# Append the from class name on the method to uniquify it now
# that these are global methods
funcSpec.name = funcSpec.name + 'From' + fromClass.foreignTypeName
# Append this funcSpec to that class's downcast methods
fromClass.downcastMethods.append(funcSpec)
# fromClass.downcastMethods.append(funcSpec)
self.environment.addDowncastFunction(funcSpec)
def constructConstructorSpecifications(self, typeIndex):
funcSpecs = []
@ -532,8 +563,14 @@ class FFIInterrogateDatabase:
def addEnvironmentTypes(self):
for descriptor in self.typeIndexMap.values():
self.environment.addType(descriptor, descriptor.foreignTypeName)
def functionInCModule(self, funcIndex, CModuleName):
if interrogate_function_has_module_name(funcIndex):
moduleName = 'lib' + interrogate_function_module_name(funcIndex)
return (moduleName == CModuleName)
def constructGlobal(self, globalIndex):
def constructGlobal(self, globalIndex, CModuleName):
# We really do not need the descriptor for the value, just
# the getter and setter
# typeIndex = interrogate_element_type(globalIndex)
@ -541,12 +578,18 @@ class FFIInterrogateDatabase:
if interrogate_element_has_getter(globalIndex):
getterIndex = interrogate_element_getter(globalIndex)
# If this function is not in this Cmodule just return
if not self.functionInCModule(getterIndex, CModuleName):
return None
getter = self.constructGlobalFunction(getterIndex)
else:
getter = None
if interrogate_element_has_setter(globalIndex):
setterIndex = interrogate_element_setter(globalIndex)
# If this function is not in this Cmodule just return
if not self.functionInCModule(setterIndex, CModuleName):
return None
setter = self.constructGlobalFunction(setterIndex)
else:
setter = None
@ -570,21 +613,23 @@ class FFIInterrogateDatabase:
funcSpec.index = globalIndex
return funcSpec
def addGlobalFunctions(self):
def addGlobalFunctions(self, CModuleName):
numGlobals = interrogate_number_of_global_functions()
for i in range(numGlobals):
funcIndex = interrogate_get_global_function(i)
newGlob = self.constructGlobalFunction(funcIndex)
if newGlob:
self.environment.addGlobalFunction(newGlob)
if self.functionInCModule(funcIndex, CModuleName):
newGlob = self.constructGlobalFunction(funcIndex)
if newGlob:
self.environment.addGlobalFunction(newGlob)
"""
# Take all the global functions that have a Panda Class as their
# first argument and make them class methods on that class
# For example the global function
# get_distance(node1, node2)
# becomes:
# node1.getDistance(node2)
# Functions that do not get moved will be stored here temporarily
tempGlobalFunctions = []
for funcSpec in self.environment.globalFunctions:
@ -602,15 +647,17 @@ class FFIInterrogateDatabase:
else:
# Copy this function into the temp list
tempGlobalFunctions.append(funcSpec)
# Now copy the temp list back over the real list
# Copy the temp list back over the real list
self.environment.globalFunctions = tempGlobalFunctions
"""
def addGlobalValues(self):
def addGlobalValues(self, CModuleName):
numGlobals = interrogate_number_of_globals()
for i in range(numGlobals):
globalIndex = interrogate_get_global(i)
newGlob = self.constructGlobal(globalIndex)
self.environment.addGlobalValue(newGlob)
newGlob = self.constructGlobal(globalIndex, CModuleName)
if newGlob:
self.environment.addGlobalValue(newGlob)
def constructManifest(self, manifestIndex):
@ -656,18 +703,50 @@ class FFIInterrogateDatabase:
FFIConstants.notify.info( 'Generating static class...')
generateStaticClass(codeDir)
# Import all the C++ modules
for CModuleName in FFIConstants.CodeModuleNameList:
self.generateCodeLib(codeDir, extensionsDir, CModuleName)
# For convenience, output a file that imports all the c module files
file = open(os.path.join(codeDir, FFIConstants.importModuleName + '.py'), 'w')
for CModuleName in FFIConstants.CodeModuleNameList:
file.write('from ' + CModuleName + 'Modules import *\n')
file.close()
FFIConstants.notify.info( 'Compiling code...')
compileall.compile_dir(codeDir)
def generateCodeLib(self, codeDir, extensionsDir, CModuleName):
# Reset the environment so we are clean from any old modules
self.environment.reset()
FFIConstants.notify.info('==================================================')
FFIConstants.notify.info('Importing code library: ' + CModuleName)
exec('import ' + CModuleName)
self.updateBindings(CModuleName)
FFIConstants.notify.info( 'Generating type code...')
for type in self.environment.types.values():
# Do not generate code for nested types at the top level
if (not type.isNested):
type.generateGlobalCode(codeDir, extensionsDir)
FFIConstants.notify.info( 'Generating global downcast code...')
downcastFile = constructDowncastFile(codeDir, CModuleName)
# Output all the imports based on this list of functions
outputGlobalFileImports(downcastFile, self.environment.downcastFunctions, CModuleName)
for type in self.environment.downcastFunctions:
type.generateGlobalCode(downcastFile)
FFIConstants.notify.info( 'Generating global value code...')
globalFile = constructGlobalFile(codeDir)
globalFile = constructGlobalFile(codeDir, CModuleName)
# Make a list of all the global functions. This includes the normal
# global functions as well as the getters and setters on all the
# global values. This list is used to figure out what files to import
# Only include the global functions from the current C module
globalFunctions = self.environment.globalFunctions
for globalValue in self.environment.globalValues:
if globalValue.getter:
@ -675,7 +754,7 @@ class FFIInterrogateDatabase:
if globalValue.setter:
globalFunctions.append(globalValue.setter)
# Output all the imports based on this list of functions
outputGlobalFileImports(globalFile, globalFunctions)
outputGlobalFileImports(globalFile, globalFunctions, CModuleName)
FFIConstants.notify.info( 'Generating global value code...')
for type in self.environment.globalValues:
@ -692,21 +771,17 @@ class FFIInterrogateDatabase:
globalFile.close()
FFIConstants.notify.info( 'Generating import code...')
importFile = constructImportFile(codeDir)
outputImportFileImports(importFile, self.environment.types.values())
importFile = constructImportFile(codeDir, CModuleName)
outputImportFileImports(importFile, self.environment.types.values(), CModuleName)
FFIConstants.notify.info( 'Compiling code...')
compileall.compile_dir(codeDir)
def updateBindings(self):
def updateBindings(self, CModuleName):
FFIConstants.notify.info( 'Updating Bindings')
FFIConstants.notify.info( 'Adding Types...')
self.addTypes()
FFIConstants.notify.info( 'Adding global values...')
self.addGlobalValues()
self.addGlobalValues(CModuleName)
FFIConstants.notify.info( 'Adding global functions...')
self.addGlobalFunctions()
self.addGlobalFunctions(CModuleName)
FFIConstants.notify.info( 'Adding manifests symbols...')
self.addManifestSymbols()
FFIConstants.notify.info( 'Adding environment types...')

View File

@ -235,29 +235,35 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
"""
Return a list of all the C modules this class references
"""
moduleList = []
for method in (self.constructors + [self.destructor] + self.instanceMethods
+ self.upcastMethods + self.downcastMethods
+ self.staticMethods + self.globalMethods):
if method:
if (not (method.typeDescriptor.moduleName in moduleList)):
moduleList.append(method.typeDescriptor.moduleName)
# Now look at all the methods that we might inherit if we are at
# a multiple inheritance node and get their C modules
if (len(self.parentTypes) >= 2):
for parentType in self.parentTypes:
for method in parentType.instanceMethods:
if (not (method.typeDescriptor.moduleName in moduleList)):
moduleList.append(method.typeDescriptor.moduleName)
for method in parentType.upcastMethods:
if (not (method.typeDescriptor.moduleName in moduleList)):
moduleList.append(method.typeDescriptor.moduleName)
for method in parentType.globalMethods:
if (not (method.typeDescriptor.moduleName in moduleList)):
moduleList.append(method.typeDescriptor.moduleName)
return moduleList
try:
# Prevent from doing the work twice
# if CModules is already defined, just return it
return self.CModules
except:
# Otherwise, it must be our first time through, do the real work
self.CModules = []
for method in (self.constructors + [self.destructor] + self.instanceMethods
+ self.upcastMethods + self.downcastMethods
+ self.staticMethods + self.globalMethods):
if method:
if (not (method.typeDescriptor.moduleName in self.CModules)):
self.CModules.append(method.typeDescriptor.moduleName)
# Now look at all the methods that we might inherit if we are at
# a multiple inheritance node and get their C modules
if (len(self.parentTypes) >= 2):
for parentType in self.parentTypes:
for method in parentType.instanceMethods:
if (not (method.typeDescriptor.moduleName in self.CModules)):
self.CModules.append(method.typeDescriptor.moduleName)
for method in parentType.upcastMethods:
if (not (method.typeDescriptor.moduleName in self.CModules)):
self.CModules.append(method.typeDescriptor.moduleName)
for method in parentType.globalMethods:
if (not (method.typeDescriptor.moduleName in self.CModules)):
self.CModules.append(method.typeDescriptor.moduleName)
return self.CModules
def getReturnTypeModules(self):
@ -586,6 +592,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
indent(file, 0, '# Import all the C modules this class uses\n')
for moduleName in self.getCModules():
indent(file, 0, 'import ' + moduleName + '\n')
indent(file, 0, 'import ' + moduleName + 'Downcasts\n')
indent(file, 0, '\n')
indent(file, 0, 'import FFIExternalObject\n')
@ -637,7 +644,12 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
# that we will call later
if (nesting==0):
indent(file, nesting, '# Delay the definition of this class until all the imports are done\n')
indent(file, nesting, '# Make sure we only define this class once\n')
indent(file, nesting, 'classDefined = 0\n')
indent(file, nesting, 'def generateClass_' + self.foreignTypeName + '():\n')
indent(file, nesting, ' if classDefined: return\n')
indent(file, nesting, ' global classDefined\n')
indent(file, nesting, ' classDefined = 1\n')
# Start the class definition indented a space to account for the function
indent(file, nesting, ' class ' + self.foreignTypeName)
else:
@ -655,13 +667,22 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
file.write(parentTypeName + '.' + parentTypeName)
file.write(', ')
file.write('FFIExternalObject.FFIExternalObject):\n')
# Store the class C modules for the class so they do not
# get garbage collected before we do
# TODO: this did not appear to work
indent(file, nesting+1, '__CModules__ = [')
for moduleName in self.getCModules():
file.write(moduleName + ',')
file.write(']\n')
# Store the downcast function modules so the FFIExternalObject
# can index into them to find the downcast functions
indent(file, nesting+1, '__CModuleDowncasts__ = [')
for moduleName in self.getCModules():
file.write(moduleName + 'Downcasts,')
file.write(']\n')
def outputClassFooter(self, file):
indent(file, 0, " # When this class gets defined, put it in this module's namespace\n")
@ -744,8 +765,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
if userManagesMemory:
indent(file, nesting, 'returnObject.userManagesMemory = 1\n')
if needsDowncast:
indent(file, nesting, 'downcastObject = returnObject.setPointer()\n')
indent(file, nesting, 'return downcastObject\n')
indent(file, nesting, 'return returnObject.setPointer()\n')
else:
indent(file, nesting, 'return returnObject\n')

View File

@ -109,6 +109,5 @@ else:
# Ok, now we can start generating code
import FFIInterrogateDatabase
db = FFIInterrogateDatabase.FFIInterrogateDatabase()
db.updateBindings()
db.generateCode(outputDir, extensionsDir)

View File

@ -42,12 +42,13 @@ class ShowBase:
self.dataRoot = NodePath(NamedNode('dataRoot'), DataRelation.getClassType())
self.dataUnused = NodePath(NamedNode('dataUnused'), DataRelation.getClassType())
self.pipe = makeGraphicsPipe()
self.win = self.pipe.makeGraphicsWindow(self.renderTop.node(),
self.camera.node(),
self.dataRoot.node(),
self.initialState)
self.win = makeGraphicsWindow(self.pipe,
self.renderTop.node(),
self.camera.node(),
self.dataRoot.node(),
self.initialState)
self.render2d = NodePath(self.win.setupPanda2d())
self.render2d = NodePath(setupPanda2d(self.win))
# This is a list of cams associated with the display region's cameras
self.camList = []
for camera in self.cameraList:
@ -105,13 +106,13 @@ class ShowBase:
self.eventMgr.shutdown()
def toggleBackface(self):
self.initialState.toggleBackface()
toggleBackface(self.initialState)
def toggleTexture(self):
self.initialState.toggleTexture()
toggleTexture(self.initialState)
def toggleWireframe(self):
self.initialState.toggleWireframe()
toggleWireframe(self.initialState)
def disableMouse(self):
self.drive.reparentTo(self.dataUnused)

View File

@ -8,20 +8,22 @@ exit = -1
done = 0
cont = 1
# Store the global clock
globalClock = ClockObject.getGlobalClock()
def getTimeFrame():
# WARNING: If you are testing tasks without an igloop,
# you must manually tick the clock
# Ask for the time last frame
t = ClockObject.getGlobalClock().getTime()
t = globalClock.getTime()
# Set the clock to have last frame's time in case we were
# Paused at the prompt for a long time
ClockObject.getGlobalClock().setTime(t)
globalClock.setTime(t)
# Get the new frame count
f = ClockObject.getGlobalClock().getFrameCount()
f = globalClock.getFrameCount()
return t, f