Browse Source

*** empty log message ***

Joe Shochet 25 years ago
parent
commit
0901fd9c20

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

@@ -3,10 +3,6 @@
 from  DirectNotifyGlobal import *
 from  DirectNotifyGlobal import *
 notify = directNotify.newCategory("FFI")
 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
 # This is the name of the file that the importing code will be stored
 importModuleName = 'PandaModules'
 importModuleName = 'PandaModules'
 
 

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

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

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

@@ -4,26 +4,19 @@ import TypedObject
 
 
 WrapperClassMap = {}
 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:
 class FFIExternalObject:
@@ -32,23 +25,52 @@ class FFIExternalObject:
         self.userManagesMemory = 0
         self.userManagesMemory = 0
         # Start with a null this pointer
         # Start with a null this pointer
         self.this = 0
         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):
     def setPointer(self):
         if (self.this == 0):
         if (self.this == 0):
             # Null pointer, return None
             # Null pointer, return None
             return None
             return None
         # If it is not a typed object, our work is done, just return the object
         # 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
             return self
         # Ok, it is a typed object. See what type it really is and downcast
         # Ok, it is a typed object. See what type it really is and downcast
         # to that type (if necessary)
         # 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
         # We do not need to downcast if we already have the same class
         if (exactWrapperClass and (exactWrapperClass != self.__class__)):
         if (exactWrapperClass and (exactWrapperClass != self.__class__)):
             # Create a new wrapper class instance
             # Create a new wrapper class instance
@@ -71,16 +93,10 @@ class FFIExternalObject:
         else:
         else:
             return None
             return None
         
         
-    def registerInTypeMap(self):
-        global WrapperClassMap
-        if self.isTypedObject():
-            typeIndex = self.__class__.getClassType().getIndex()
-            WrapperClassMap[typeIndex] = self.__class__
-
     def downcast(self, specificClass):
     def downcast(self, specificClass):
         FFIConstants.notify.debug('downcasting from %s to %s' % \
         FFIConstants.notify.debug('downcasting from %s to %s' % \
             (self.__class__.__name__, specificClass.__name__))
             (self.__class__.__name__, specificClass.__name__))
-        downcastChain = getDowncastFunctions(specificClass, self.__class__, [])
+        downcastChain = self.getDowncastFunctions(specificClass, self.__class__, [])
         FFIConstants.notify.debug('downcast chain: ' + `downcastChain`)
         FFIConstants.notify.debug('downcast chain: ' + `downcastChain`)
         newObject = self
         newObject = self
         if (downcastChain == None):
         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
 # to be dependent on the name of the interrogate library in this code
 exec('from ' + FFIConstants.InterrogateModuleName + ' import *')
 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
     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
     return file
 
 
-def constructImportFile(codeDir):
+
+def constructImportFile(codeDir, CModuleName):
     """
     """
     Open a file that will hold the global values and functions code
     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
     return file
 
 
-def outputGlobalFileImports(file, methodList):
+def outputGlobalFileImports(file, methodList, CModuleName):
     # Print the standard header
     # Print the standard header
     file.write(FFIConstants.generatedHeader)
     file.write(FFIConstants.generatedHeader)
 
 
@@ -48,15 +52,34 @@ def outputGlobalFileImports(file, methodList):
     file.write('import types\n')
     file.write('import types\n')
 
 
     # Import the C modules
     # 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')
         file.write('import ' + CModuleName + '\n')
 
 
     moduleList = []
     moduleList = []
     for method in methodList:
     for method in methodList:
         returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor()
         returnType = method.typeDescriptor.returnType.recursiveTypeDescriptor()
-        if (not (returnType.foreignTypeName in moduleList)):
+        returnTypeName = returnType.foreignTypeName
+        if (not (returnTypeName in moduleList)):
             if (returnType.__class__ == FFITypes.ClassTypeDescriptor):
             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:
     for moduleName in moduleList:
         file.write('import ' + moduleName + '\n')
         file.write('import ' + moduleName + '\n')
@@ -64,7 +87,7 @@ def outputGlobalFileImports(file, methodList):
     file.write('\n')
     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
     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('import ' + FFIConstants.InterrogateModuleName + '\n')
     file.write('\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)
     # Filter out only the class and enum type descriptors (not const, pointers, etc)
     classTypeList = []
     classTypeList = []
@@ -96,12 +117,9 @@ def outputImportFileImports(file, typeList):
     classTypeList.sort(FFIOverload.inheritanceLevelSort)
     classTypeList.sort(FFIOverload.inheritanceLevelSort)
 
 
     moduleList = []
     moduleList = []
-    for type in classTypeList:    
+    for type in classTypeList:
         moduleList.append(type.foreignTypeName)
         moduleList.append(type.foreignTypeName)
 
 
-    file.write('import FFIExternalObject\n')
-    file.write('\n')
-
     file.write('# Import enums into the global name space\n')
     file.write('# Import enums into the global name space\n')
     for type in enumTypeList:
     for type in enumTypeList:
         file.write('from ' + type.enumName + ' import *\n')
         file.write('from ' + type.enumName + ' import *\n')
@@ -113,25 +131,28 @@ def outputImportFileImports(file, typeList):
     file.write('\n')
     file.write('\n')
 
 
     file.write('# Import the global module file into our name space\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('\n')
 
 
-    file.write('# Now generate the classes\n')
+    file.write('# Generate the classes\n')
     for moduleName in moduleList:
     for moduleName in moduleList:
         file.write(moduleName + '.generateClass_' + moduleName + '()\n')
         file.write(moduleName + '.generateClass_' + moduleName + '()\n')
     file.write('\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:
     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('\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:
     for moduleName in moduleList:
-        file.write(moduleName + ' = ' + moduleName + '.' + moduleName + '\n')
+        file.write('registerInTypeMap(' + moduleName + ')\n')
     file.write('\n')
     file.write('\n')
 
 
+
+
 def generateStaticClass(codeDir):
 def generateStaticClass(codeDir):
     """
     """
     Create a file that will hold the static class definition
     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
         built into the class they are being downcast from. For instance, a method
         downcastToNode(ptrBoundedObject) will appear in Node's list of methods
         downcastToNode(ptrBoundedObject) will appear in Node's list of methods
         but should be compiled into BoundedObject's class
         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)
         numFuncs = interrogate_type_number_of_derivations(typeIndex)
         for i in range(numFuncs):
         for i in range(numFuncs):
@@ -481,15 +506,21 @@ class FFIInterrogateDatabase:
                     funcIndex = interrogate_type_get_downcast(typeIndex, i)
                     funcIndex = interrogate_type_get_downcast(typeIndex, i)
                     typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
                     typeDescs = self.constructFunctionTypeDescriptors(funcIndex)
                     for typeDesc in typeDescs:
                     for typeDesc in typeDescs:
-                        funcSpec = FFISpecs.MethodSpecification()
+                        funcSpec = FFISpecs.GlobalFunctionSpecification()
                         funcSpec.name = FFIRename.methodNameFromCppName(
                         funcSpec.name = FFIRename.methodNameFromCppName(
                             interrogate_function_name(funcIndex))
                             interrogate_function_name(funcIndex))
                         funcSpec.typeDescriptor = typeDesc
                         funcSpec.typeDescriptor = typeDesc
                         funcSpec.index = funcIndex
                         funcSpec.index = funcIndex
                         # Here we look for the class in the first argument
                         # Here we look for the class in the first argument
                         fromClass = typeDesc.argumentTypes[0].typeDescriptor.recursiveTypeDescriptor()
                         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
                         # 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):
     def constructConstructorSpecifications(self, typeIndex):
         funcSpecs = []
         funcSpecs = []
@@ -532,8 +563,14 @@ class FFIInterrogateDatabase:
     def addEnvironmentTypes(self):
     def addEnvironmentTypes(self):
         for descriptor in self.typeIndexMap.values():
         for descriptor in self.typeIndexMap.values():
             self.environment.addType(descriptor, descriptor.foreignTypeName)
             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
         # We really do not need the descriptor for the value, just
         # the getter and setter
         # the getter and setter
         # typeIndex = interrogate_element_type(globalIndex)
         # typeIndex = interrogate_element_type(globalIndex)
@@ -541,12 +578,18 @@ class FFIInterrogateDatabase:
         
         
         if interrogate_element_has_getter(globalIndex):
         if interrogate_element_has_getter(globalIndex):
             getterIndex = interrogate_element_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)
             getter = self.constructGlobalFunction(getterIndex)
         else:
         else:
             getter = None
             getter = None
 
 
         if interrogate_element_has_setter(globalIndex):
         if interrogate_element_has_setter(globalIndex):
             setterIndex = interrogate_element_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)
             setter = self.constructGlobalFunction(setterIndex)
         else:
         else:
             setter = None
             setter = None
@@ -570,21 +613,23 @@ class FFIInterrogateDatabase:
             funcSpec.index = globalIndex
             funcSpec.index = globalIndex
             return funcSpec
             return funcSpec
         
         
-    def addGlobalFunctions(self):
+    def addGlobalFunctions(self, CModuleName):
         numGlobals = interrogate_number_of_global_functions()
         numGlobals = interrogate_number_of_global_functions()
         for i in range(numGlobals):
         for i in range(numGlobals):
             funcIndex = interrogate_get_global_function(i)
             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
         # Take all the global functions that have a Panda Class as their
         # first argument and make them class methods on that class
         # first argument and make them class methods on that class
         # For example the global function
         # For example the global function
         #    get_distance(node1, node2)
         #    get_distance(node1, node2)
         # becomes:
         # becomes:
         #    node1.getDistance(node2)
         #    node1.getDistance(node2)
-       
+
         # Functions that do not get moved will be stored here temporarily
         # Functions that do not get moved will be stored here temporarily
         tempGlobalFunctions = []
         tempGlobalFunctions = []
         for funcSpec in self.environment.globalFunctions:
         for funcSpec in self.environment.globalFunctions:
@@ -602,15 +647,17 @@ class FFIInterrogateDatabase:
             else:
             else:
                 # Copy this function into the temp list
                 # Copy this function into the temp list
                 tempGlobalFunctions.append(funcSpec)
                 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
         self.environment.globalFunctions = tempGlobalFunctions
+        """
                     
                     
-    def addGlobalValues(self):
+    def addGlobalValues(self, CModuleName):
         numGlobals = interrogate_number_of_globals()
         numGlobals = interrogate_number_of_globals()
         for i in range(numGlobals):
         for i in range(numGlobals):
             globalIndex = interrogate_get_global(i)
             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):
     def constructManifest(self, manifestIndex):
@@ -656,18 +703,50 @@ class FFIInterrogateDatabase:
         FFIConstants.notify.info( 'Generating static class...')
         FFIConstants.notify.info( 'Generating static class...')
         generateStaticClass(codeDir)
         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...')
         FFIConstants.notify.info( 'Generating type code...')
         for type in self.environment.types.values():
         for type in self.environment.types.values():
             # Do not generate code for nested types at the top level
             # Do not generate code for nested types at the top level
             if (not type.isNested):
             if (not type.isNested):
                 type.generateGlobalCode(codeDir, extensionsDir)
                 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...')
         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
         # 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 functions as well as the getters and setters on all the
         # global values. This list is used to figure out what files to import
         # 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
         globalFunctions = self.environment.globalFunctions
         for globalValue in self.environment.globalValues:
         for globalValue in self.environment.globalValues:
             if globalValue.getter:
             if globalValue.getter:
@@ -675,7 +754,7 @@ class FFIInterrogateDatabase:
             if globalValue.setter:
             if globalValue.setter:
                 globalFunctions.append(globalValue.setter)
                 globalFunctions.append(globalValue.setter)
         # Output all the imports based on this list of functions
         # Output all the imports based on this list of functions
-        outputGlobalFileImports(globalFile, globalFunctions)
+        outputGlobalFileImports(globalFile, globalFunctions, CModuleName)
 
 
         FFIConstants.notify.info( 'Generating global value code...')
         FFIConstants.notify.info( 'Generating global value code...')
         for type in self.environment.globalValues:
         for type in self.environment.globalValues:
@@ -692,21 +771,17 @@ class FFIInterrogateDatabase:
         globalFile.close()
         globalFile.close()
 
 
         FFIConstants.notify.info( 'Generating import code...')
         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( 'Updating Bindings')
         FFIConstants.notify.info( 'Adding Types...')
         FFIConstants.notify.info( 'Adding Types...')
         self.addTypes()
         self.addTypes()
         FFIConstants.notify.info( 'Adding global values...')
         FFIConstants.notify.info( 'Adding global values...')
-        self.addGlobalValues()
+        self.addGlobalValues(CModuleName)
         FFIConstants.notify.info( 'Adding global functions...')
         FFIConstants.notify.info( 'Adding global functions...')
-        self.addGlobalFunctions()
+        self.addGlobalFunctions(CModuleName)
         FFIConstants.notify.info( 'Adding manifests symbols...')
         FFIConstants.notify.info( 'Adding manifests symbols...')
         self.addManifestSymbols()
         self.addManifestSymbols()
         FFIConstants.notify.info( 'Adding environment types...')
         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
         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):
     def getReturnTypeModules(self):
@@ -586,6 +592,7 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
         indent(file, 0, '# Import all the C modules this class uses\n')
         indent(file, 0, '# Import all the C modules this class uses\n')
         for moduleName in self.getCModules():
         for moduleName in self.getCModules():
             indent(file, 0, 'import ' + moduleName + '\n')            
             indent(file, 0, 'import ' + moduleName + '\n')            
+            indent(file, 0, 'import ' + moduleName + 'Downcasts\n')
         indent(file, 0, '\n')
         indent(file, 0, '\n')
         indent(file, 0, 'import FFIExternalObject\n')
         indent(file, 0, 'import FFIExternalObject\n')
         
         
@@ -637,7 +644,12 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
         # that we will call later
         # that we will call later
         if (nesting==0):
         if (nesting==0):
             indent(file, nesting, '# Delay the definition of this class until all the imports are done\n')
             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, '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
             # Start the class definition indented a space to account for the function
             indent(file, nesting, ' class ' + self.foreignTypeName)
             indent(file, nesting, ' class ' + self.foreignTypeName)
         else:
         else:
@@ -655,13 +667,22 @@ class ClassTypeDescriptor(BaseTypeDescriptor):
             file.write(parentTypeName + '.' + parentTypeName)
             file.write(parentTypeName + '.' + parentTypeName)
             file.write(', ')
             file.write(', ')
         file.write('FFIExternalObject.FFIExternalObject):\n')
         file.write('FFIExternalObject.FFIExternalObject):\n')
+
         # Store the class C modules for the class so they do not
         # Store the class C modules for the class so they do not
         # get garbage collected before we do
         # get garbage collected before we do
+        # TODO: this did not appear to work
         indent(file, nesting+1, '__CModules__ = [')
         indent(file, nesting+1, '__CModules__ = [')
         for moduleName in self.getCModules():
         for moduleName in self.getCModules():
             file.write(moduleName + ',')
             file.write(moduleName + ',')
         file.write(']\n')
         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):
     def outputClassFooter(self, file):
         indent(file, 0, " # When this class gets defined, put it in this module's namespace\n")
         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:
         if userManagesMemory:
             indent(file, nesting, 'returnObject.userManagesMemory = 1\n')
             indent(file, nesting, 'returnObject.userManagesMemory = 1\n')
         if needsDowncast:
         if needsDowncast:
-            indent(file, nesting, 'downcastObject = returnObject.setPointer()\n')
-            indent(file, nesting, 'return downcastObject\n')
+            indent(file, nesting, 'return returnObject.setPointer()\n')
         else:
         else:
             indent(file, nesting, 'return returnObject\n')
             indent(file, nesting, 'return returnObject\n')
             
             

+ 0 - 1
direct/src/ffi/generatePythonCode

@@ -109,6 +109,5 @@ else:
 # Ok, now we can start generating code
 # Ok, now we can start generating code
 import FFIInterrogateDatabase
 import FFIInterrogateDatabase
 db = FFIInterrogateDatabase.FFIInterrogateDatabase()
 db = FFIInterrogateDatabase.FFIInterrogateDatabase()
-db.updateBindings()
 db.generateCode(outputDir, extensionsDir)
 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.dataRoot = NodePath(NamedNode('dataRoot'), DataRelation.getClassType())
         self.dataUnused = NodePath(NamedNode('dataUnused'), DataRelation.getClassType())
         self.dataUnused = NodePath(NamedNode('dataUnused'), DataRelation.getClassType())
         self.pipe = makeGraphicsPipe()
         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
         # This is a list of cams associated with the display region's cameras
         self.camList = []
         self.camList = []
         for camera in self.cameraList:
         for camera in self.cameraList:
@@ -105,13 +106,13 @@ class ShowBase:
         self.eventMgr.shutdown()
         self.eventMgr.shutdown()
 
 
     def toggleBackface(self):
     def toggleBackface(self):
-        self.initialState.toggleBackface()
+        toggleBackface(self.initialState)
 
 
     def toggleTexture(self):
     def toggleTexture(self):
-        self.initialState.toggleTexture()
+        toggleTexture(self.initialState)
 
 
     def toggleWireframe(self):
     def toggleWireframe(self):
-        self.initialState.toggleWireframe()
+        toggleWireframe(self.initialState)
 
 
     def disableMouse(self):
     def disableMouse(self):
         self.drive.reparentTo(self.dataUnused)
         self.drive.reparentTo(self.dataUnused)

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

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