#-*- coding: UTF-8 -*- """ Some fancy helper functions. """ import os import ctypes from ctypes import POINTER import operator import numpy from numpy import linalg import logging;logger = logging.getLogger("pyassimp") from .errors import AssimpError additional_dirs, ext_whitelist = [],[] # populate search directories and lists of allowed file extensions # depending on the platform we're running on. if os.name=='posix': additional_dirs.append('/usr/lib/') additional_dirs.append('/usr/local/lib/') # note - this won't catch libassimp.so.N.n, but # currently there's always a symlink called # libassimp.so in /usr/local/lib. ext_whitelist.append('.so') elif os.name=='nt': ext_whitelist.append('.dll') #print(additional_dirs) def vec2tuple(x): """ Converts a VECTOR3D to a Tuple """ return (x.x, x.y, x.z) def transform(vector3, matrix4x4): """ Apply a transformation matrix on a 3D vector. :param vector3: a numpy array with 3 elements :param matrix4x4: a numpy 4x4 matrix """ return numpy.dot(matrix4x4, numpy.append(vector3, 1.)) def get_bounding_box(scene): bb_min = [1e10, 1e10, 1e10] # x,y,z bb_max = [-1e10, -1e10, -1e10] # x,y,z return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, linalg.inv(scene.rootnode.transformation)) def get_bounding_box_for_node(node, bb_min, bb_max, transformation): transformation = numpy.dot(transformation, node.transformation) for mesh in node.meshes: for v in mesh.vertices: v = transform(v, transformation) bb_min[0] = min(bb_min[0], v[0]) bb_min[1] = min(bb_min[1], v[1]) bb_min[2] = min(bb_min[2], v[2]) bb_max[0] = max(bb_max[0], v[0]) bb_max[1] = max(bb_max[1], v[1]) bb_max[2] = max(bb_max[2], v[2]) for child in node.children: bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation) return bb_min, bb_max def try_load_functions(library,dll,candidates): """try to functbind to aiImportFile and aiReleaseImport library - path to current lib dll - ctypes handle to it candidates - receives matching candidates They serve as signal functions to detect assimp, also they're currently the only functions we need. insert (library,aiImportFile,aiReleaseImport,dll) into 'candidates' if successful. """ try: load = dll.aiImportFile release = dll.aiReleaseImport except AttributeError: #OK, this is a library, but it has not the functions we need pass else: #Library found! from .structs import Scene load.restype = POINTER(Scene) candidates.append((library, load, release, dll)) def search_library(): """Loads the assimp-Library. result (load-function, release-function) exception AssimpError if no library is found """ #this path folder = os.path.dirname(__file__) # silence 'DLL not found' message boxes on win try: ctypes.windll.kernel32.SetErrorMode(0x8007) except AttributeError: pass candidates = [] # test every file for curfolder in [folder]+additional_dirs: for filename in os.listdir(curfolder): # our minimum requirement for candidates is that # they should contain 'assimp' somewhere in # their name if filename.lower().find('assimp')==-1 or\ os.path.splitext(filename)[-1].lower() not in ext_whitelist: continue library = os.path.join(curfolder, filename) logger.debug('Try ' + library) try: dll = ctypes.cdll.LoadLibrary(library) except Exception as e: logger.warning(str(e)) # OK, this except is evil. But different OSs will throw different # errors. So just ignore any errors. continue try_load_functions(library,dll,candidates) if not candidates: # no library found raise AssimpError("assimp library not found") else: # get the newest library candidates = map(lambda x: (os.lstat(x[0])[-2], x), candidates) res = max(candidates, key=operator.itemgetter(0))[1] logger.debug('Using assimp library located at ' + res[0]) # XXX: if there are 1000 dll/so files containing 'assimp' # in their name, do we have all of them in our address # space now until gc kicks in? # XXX: take version postfix of the .so on linux? return res[1:]