Prechádzať zdrojové kódy

*** empty log message ***

Joe Shochet 25 rokov pred
rodič
commit
0901fd9c20

+ 0 - 4
direct/src/ffi/FFIConstants.py

@@ -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'
 

+ 6 - 0
direct/src/ffi/FFIEnvironment.py

@@ -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):

+ 49 - 36
direct/src/ffi/FFIExternalObject.py

@@ -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:
 
 
 
-
-
-
     

+ 126 - 51
direct/src/ffi/FFIInterrogateDatabase.py

@@ -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, CModuleName):
+    """
+    Open a file that will hold the global values and functions code
+    """
+    file = open(os.path.join(codeDir, CModuleName + 'Globals' + '.py'), 'w')
+    return file
+
 
-def constructGlobalFile(codeDir):
+def constructDowncastFile(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 + 'Downcasts' + '.py'), 'w')
     return file
 
-def constructImportFile(codeDir):
+
+def constructImportFile(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 + 'Modules' + '.py'), 'w')
     return file
 
-def outputGlobalFileImports(file, methodList):
+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')
+    file.write('# Copy the classes into our own namespace\n')
     for moduleName in moduleList:
-        file.write('obj = ' + moduleName + '.' + moduleName + '(None)\n')
-        file.write('obj.registerInTypeMap()\n')
+        file.write(moduleName + ' = ' + moduleName + '.' + moduleName + '\n')
     file.write('\n')
 
-    file.write('# Now copy the classes into our own namespace\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(moduleName + ' = ' + moduleName + '.' + moduleName + '\n')
+        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())
-
-        FFIConstants.notify.info( 'Compiling code...')
-        compileall.compile_dir(codeDir)
-        
+        importFile = constructImportFile(codeDir, CModuleName)
+        outputImportFileImports(importFile, self.environment.types.values(), CModuleName)
 
-    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...')

+ 46 - 26
direct/src/ffi/FFITypes.py

@@ -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')
             

+ 0 - 1
direct/src/ffi/generatePythonCode

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

+ 9 - 8
direct/src/showbase/ShowBase.py

@@ -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)

+ 5 - 3
direct/src/showbase/Task.py

@@ -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