Poodletooth-iLand/panda/direct/ffi/panda3d.py

276 lines
9.4 KiB
Python
Raw Normal View History

2015-03-03 16:10:12 -06:00
#!/bin/true
import os, sys, imp
panda3d_modules = {
"core" :("libpandaexpress", "libpanda"),
"dtoolconfig" : "libp3dtoolconfig",
"physics" : "libpandaphysics",
"fx" : "libpandafx",
"direct" : "libp3direct",
"egg" : "libpandaegg",
"ode" : "libpandaode",
"bullet" : "libpandabullet",
"vision" : "libp3vision",
"physx" : "libpandaphysx",
"ai" : "libpandaai",
"awesomium" : "libp3awesomium",
"speedtree" : "libpandaspeedtree",
"rocket" :("_rocketcore", "_rocketcontrols", "libp3rocket"),
"vrpn" : "libp3vrpn",
}
class panda3d_import_manager:
# Important: store a reference to the sys and os modules, as
# all references in the global namespace will be reset.
os = os
sys = sys
imp = imp
__libraries__ = {}
# Figure out the dll suffix (commonly, _d for windows debug builds),
# and the dll extension.
dll_suffix = ''
dll_exts = ('.pyd', '.so')
if sys.platform == "win32":
dll_exts = ('.pyd', '.dll')
# We allow the caller to preload dll_suffix into the sys module.
dll_suffix = getattr(sys, 'dll_suffix', None)
if dll_suffix is None:
# Otherwise, we try to determine it from the executable name:
# python_d.exe implies _d across the board.
dll_suffix = ''
if sys.executable.endswith('_d.exe'):
dll_suffix = '_d'
# On OSX, extension modules can be loaded from either .so or .dylib.
if sys.platform == "darwin":
dll_exts = ('.pyd', '.so', '.dylib')
prepared = False
@classmethod
def __prepare(cls):
# This method only needs to be called once.
if cls.prepared:
return
cls.prepared = True
# First, we must ensure that the library path is
# modified to locate all of the dynamic libraries.
target = None
filename = "libpandaexpress" + cls.dll_suffix
for dir in cls.sys.path + [cls.sys.prefix]:
lib = cls.os.path.join(dir, filename)
for dll_ext in cls.dll_exts:
if (cls.os.path.exists(lib + dll_ext)):
target = dir
break
if target == None:
raise ImportError("Cannot find %s" % (filename))
target = cls.os.path.abspath(target)
# And add that directory to the system library path.
if cls.sys.platform == "win32":
cls.__prepend_to_path("PATH", target)
else:
cls.__prepend_to_path("LD_LIBRARY_PATH", target)
if cls.sys.platform == "darwin":
cls.__prepend_to_path("DYLD_LIBRARY_PATH", target)
@classmethod
def __prepend_to_path(cls, varname, target):
""" Prepends the given directory to the
specified search path environment variable. """
# Get the current value
if varname in cls.os.environ:
path = cls.os.environ[varname].strip(cls.os.pathsep)
else:
path = ""
# Prepend our value, if it's not already the first thing
if len(path) == 0:
cls.os.environ[varname] = target
elif not path.startswith(target):
cls.os.environ[varname] = target + cls.os.pathsep + path
@classmethod
def libimport(cls, name):
""" Imports and returns the specified library name. The
provided library name has to be without dll extension. """
if name in cls.__libraries__:
return cls.__libraries__[name]
if not cls.prepared: cls.__prepare()
# Try to import it normally first.
try:
return __import__(name)
except ImportError:
_, err, _ = cls.sys.exc_info()
if str(err) != "No module named " + name and \
str(err) != "No module named '%s'" % name:
raise
# Hm, importing normally didn't work. Let's try imp.load_dynamic.
# But first, locate the desired library.
target = None
filename = name + cls.dll_suffix
for dir in cls.sys.path + [cls.sys.prefix]:
lib = cls.os.path.join(dir, filename)
for dll_ext in cls.dll_exts:
if (cls.os.path.exists(lib + dll_ext)):
target = lib + dll_ext
break
if target:
# Once we find the first match, break all the way
# out--don't keep looking for a second match.
break
if target == None:
message = "DLL loader cannot find %s." % name
raise ImportError(message)
target = cls.os.path.abspath(target)
# Now import the file explicitly.
lib = cls.imp.load_dynamic(name, target)
cls.__libraries__[name] = lib
return lib
class panda3d_submodule(type(sys)):
""" Represents a submodule of 'panda3d' that represents a dynamic
library. This dynamic library is loaded when something is accessed
from the module. """
__manager__ = panda3d_import_manager
def __init__(self, name, library):
type(sys).__init__(self, "panda3d." + name)
self.__library__ = library
self.__libraries__ = [self.__library__]
def __load__(self):
""" Forces the library to be loaded right now. """
self.__manager__.libimport(self.__library__)
def __getattr__(self, name):
mod = self.__manager__.libimport(self.__library__)
if name == "__all__":
everything = []
for obj in mod.__dict__.keys():
if not obj.startswith("__"):
everything.append(obj)
self.__all__ = everything
return everything
elif name == "__library__":
return self.__library__
elif name == "__libraries__":
return self.__libraries__
elif name in mod.__dict__.keys():
value = mod.__dict__[name]
setattr(self, name, value)
return value
# Not found? Raise the error that Python would normally raise.
raise AttributeError("'module' object has no attribute '%s'" % name)
class panda3d_multisubmodule(type(sys)):
""" Represents a submodule of 'panda3d' that represents multiple
dynamic libraries. These are loaded when something is accessed
from the module. """
__manager__ = panda3d_import_manager
def __init__(self, name, libraries):
type(sys).__init__(self, "panda3d." + name)
self.__libraries__ = libraries
def __load__(self):
""" Forces the libraries to be loaded right now. """
err = []
for lib in self.__libraries__:
try:
self.__manager__.libimport(lib)
except ImportError:
_, msg, _ = self.__manager__.sys.exc_info()
err.append(str(msg).rstrip('.'))
if len(err) > 0:
raise ImportError(', '.join(err))
def __getattr__(self, name):
if name == "__all__":
everything = []
for lib in self.__libraries__:
for obj in self.__manager__.libimport(lib).__dict__:
if not obj.startswith("__"):
everything.append(obj)
self.__all__ = everything
return everything
elif name == "__libraries__":
return self.__libraries__
for lib in self.__libraries__:
mod = self.__manager__.libimport(lib)
if name in mod.__dict__:
value = mod.__dict__[name]
setattr(self, name, value)
return value
# Not found? Raise the error that Python would normally raise.
raise AttributeError("'module' object has no attribute '%s'" % name)
class panda3d_module(type(sys)):
""" Represents the main 'panda3d' module. """
__file__ = __file__
modules = panda3d_modules
__manager__ = panda3d_import_manager
def __load__(self):
""" Force all the libraries to be loaded right now. """
err = []
for module in self.modules:
try:
self.__manager__.sys.modules["panda3d.%s" % module].__load__()
except ImportError:
_, msg, _ = self.__manager__.sys.exc_info()
err.append(str(msg).rstrip('.'))
if len(err) > 0:
raise ImportError(', '.join(err))
def __getattr__(self, name):
if name == "__all__":
self.__all__ = name
return self.modules.keys()
elif name == "__file__":
return self.__file__
elif name in self.modules:
value = self.__manager__.sys.modules["panda3d.%s" % name]
setattr(self, name, value)
return value
# Not found? Raise the error that Python would normally raise.
raise AttributeError("'module' object has no attribute '%s'" % name)
# Create the fake module objects and insert them into sys.modules.
this = panda3d_module("panda3d")
# Loop through the module dictionary, create a fake
# module for each of them, and insert them into
# sys.modules and into the 'panda3d' fake module.
for mod, lib in panda3d_modules.items():
if isinstance(lib, tuple):
module = panda3d_multisubmodule(mod, lib)
else:
module = panda3d_submodule(mod, lib)
sys.modules["panda3d." + mod] = module
this.__dict__[mod] = module
# Important: this must be the last thing in this file
sys.modules["panda3d"] = this