You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

175 lines
5.2 KiB

  1. #-*- coding: UTF-8 -*-
  2. """
  3. Some fancy helper functions.
  4. """
  5. import os
  6. import ctypes
  7. from ctypes import POINTER
  8. import operator
  9. import numpy
  10. from numpy import linalg
  11. import logging;logger = logging.getLogger("pyassimp")
  12. from .errors import AssimpError
  13. additional_dirs, ext_whitelist = [],[]
  14. # populate search directories and lists of allowed file extensions
  15. # depending on the platform we're running on.
  16. if os.name=='posix':
  17. additional_dirs.append('/usr/lib/')
  18. additional_dirs.append('/usr/local/lib/')
  19. # note - this won't catch libassimp.so.N.n, but
  20. # currently there's always a symlink called
  21. # libassimp.so in /usr/local/lib.
  22. ext_whitelist.append('.so')
  23. # libassimp.dylib in /usr/local/lib
  24. ext_whitelist.append('.dylib')
  25. elif os.name=='nt':
  26. ext_whitelist.append('.dll')
  27. path_dirs = os.environ['PATH'].split(';')
  28. for dir_candidate in path_dirs:
  29. if 'assimp' in dir_candidate.lower():
  30. additional_dirs.append(dir_candidate)
  31. #print(additional_dirs)
  32. def vec2tuple(x):
  33. """ Converts a VECTOR3D to a Tuple """
  34. return (x.x, x.y, x.z)
  35. def transform(vector3, matrix4x4):
  36. """ Apply a transformation matrix on a 3D vector.
  37. :param vector3: a numpy array with 3 elements
  38. :param matrix4x4: a numpy 4x4 matrix
  39. """
  40. return numpy.dot(matrix4x4, numpy.append(vector3, 1.))
  41. def get_bounding_box(scene):
  42. bb_min = [1e10, 1e10, 1e10] # x,y,z
  43. bb_max = [-1e10, -1e10, -1e10] # x,y,z
  44. return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, linalg.inv(scene.rootnode.transformation))
  45. def get_bounding_box_for_node(node, bb_min, bb_max, transformation):
  46. transformation = numpy.dot(transformation, node.transformation)
  47. for mesh in node.meshes:
  48. for v in mesh.vertices:
  49. v = transform(v, transformation)
  50. bb_min[0] = min(bb_min[0], v[0])
  51. bb_min[1] = min(bb_min[1], v[1])
  52. bb_min[2] = min(bb_min[2], v[2])
  53. bb_max[0] = max(bb_max[0], v[0])
  54. bb_max[1] = max(bb_max[1], v[1])
  55. bb_max[2] = max(bb_max[2], v[2])
  56. for child in node.children:
  57. bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation)
  58. return bb_min, bb_max
  59. def try_load_functions(library,dll,candidates):
  60. """try to functbind to aiImportFile and aiReleaseImport
  61. library - path to current lib
  62. dll - ctypes handle to it
  63. candidates - receives matching candidates
  64. They serve as signal functions to detect assimp,
  65. also they're currently the only functions we need.
  66. insert (library,aiImportFile,aiReleaseImport,dll)
  67. into 'candidates' if successful.
  68. """
  69. try:
  70. load = dll.aiImportFile
  71. release = dll.aiReleaseImport
  72. except AttributeError:
  73. #OK, this is a library, but it has not the functions we need
  74. pass
  75. else:
  76. #Library found!
  77. from .structs import Scene
  78. load.restype = POINTER(Scene)
  79. candidates.append((library, load, release, dll))
  80. def search_library():
  81. """Loads the assimp-Library.
  82. result (load-function, release-function)
  83. exception AssimpError if no library is found
  84. """
  85. #this path
  86. folder = os.path.dirname(__file__)
  87. # silence 'DLL not found' message boxes on win
  88. try:
  89. ctypes.windll.kernel32.SetErrorMode(0x8007)
  90. except AttributeError:
  91. pass
  92. candidates = []
  93. # test every file
  94. for curfolder in [folder]+additional_dirs:
  95. for filename in os.listdir(curfolder):
  96. # our minimum requirement for candidates is that
  97. # they should contain 'assimp' somewhere in
  98. # their name
  99. if filename.lower().find('assimp')==-1 or\
  100. os.path.splitext(filename)[-1].lower() not in ext_whitelist:
  101. continue
  102. library = os.path.join(curfolder, filename)
  103. logger.debug('Try ' + library)
  104. try:
  105. dll = ctypes.cdll.LoadLibrary(library)
  106. except Exception as e:
  107. logger.warning(str(e))
  108. # OK, this except is evil. But different OSs will throw different
  109. # errors. So just ignore any errors.
  110. continue
  111. try_load_functions(library,dll,candidates)
  112. if not candidates:
  113. # no library found
  114. raise AssimpError("assimp library not found")
  115. else:
  116. # get the newest library
  117. candidates = map(lambda x: (os.lstat(x[0])[-2], x), candidates)
  118. res = max(candidates, key=operator.itemgetter(0))[1]
  119. logger.debug('Using assimp library located at ' + res[0])
  120. # XXX: if there are 1000 dll/so files containing 'assimp'
  121. # in their name, do we have all of them in our address
  122. # space now until gc kicks in?
  123. # XXX: take version postfix of the .so on linux?
  124. return res[1:]
  125. def hasattr_silent(object, name):
  126. """
  127. Calls hasttr() with the given parameters and preserves the legacy (pre-Python 3.2)
  128. functionality of silently catching exceptions.
  129. Returns the result of hasatter() or False if an exception was raised.
  130. """
  131. try:
  132. return hasattr(object, name)
  133. except:
  134. return False