pyassimp.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #-*- coding: UTF-8 -*-
  2. """
  3. PyAssimp
  4. This is the main-module of PyAssimp.
  5. """
  6. import structs
  7. import ctypes
  8. import os
  9. from ctypes import POINTER, c_int, c_uint, c_double, c_char, c_float
  10. #get the assimp path
  11. LIBRARY = os.path.join(os.path.dirname(__file__), "assimp.so")
  12. class AssimpError(BaseException):
  13. """
  14. If ann internal error occures.
  15. """
  16. pass
  17. class AssimpLib(object):
  18. #open library
  19. _dll = ctypes.cdll.LoadLibrary(LIBRARY)
  20. #get functions
  21. load = _dll.aiImportFile
  22. load.restype = POINTER(structs.SCENE)
  23. release = _dll.aiReleaseImport
  24. class AssimpBase(object):
  25. """
  26. Base class for all Assimp-classes.
  27. """
  28. def _load_array(self, data, count, cons):
  29. """
  30. Loads a whole array out of data, and constructs a new object. If data
  31. is NULL, an empty list will be returned.
  32. data - pointer to array
  33. count - size of the array
  34. cons - constructor
  35. result array data
  36. """
  37. if data:
  38. return [cons(data[i]) for i in range(count)]
  39. else:
  40. return []
  41. class Scene(AssimpBase):
  42. """
  43. The root structure of the imported data.
  44. Everything that was imported from the given file can be accessed from here.
  45. """
  46. #possible flags
  47. FLAGS = {1 : "AI_SCENE_FLAGS_ANIM_SKELETON_ONLY"}
  48. def __init__(self, model):
  49. """
  50. Converts the model-data to a real scene
  51. model - the raw model-data
  52. """
  53. #process data
  54. self._load(model)
  55. def _load(self, model):
  56. """
  57. Converts model from raw-data to fancy data!
  58. model - pointer to data
  59. """
  60. #store scene flags
  61. self.flags = model.flags
  62. #load mesh-data
  63. self.meshes = self._load_array(model.mMeshes,
  64. model.mNumMeshes,
  65. lambda x: Mesh(x.contents))
  66. def list_flags(self):
  67. """
  68. Returns a list of all used flags.
  69. result list of flags
  70. """
  71. return [name for (key, value) in Scene.FLAGS.iteritems()
  72. if (key & self.flags)>0]
  73. class Mesh(AssimpBase):
  74. """
  75. A mesh represents a geometry or model with a single material.
  76. It usually consists of a number of vertices and a series of primitives/faces
  77. referencing the vertices. In addition there might be a series of bones, each
  78. of them addressing a number of vertices with a certain weight. Vertex data
  79. is presented in channels with each channel containing a single per-vertex
  80. information such as a set of texture coords or a normal vector.
  81. If a data pointer is non-null, the corresponding data stream is present.
  82. A Mesh uses only a single material which is referenced by a material ID.
  83. """
  84. def __init__(self, mesh):
  85. """
  86. Loads mesh from raw-data.
  87. """
  88. #process data
  89. self._load(mesh)
  90. def _load(self, mesh):
  91. """
  92. Loads mesh-data from raw data
  93. mesh - raw mesh-data
  94. """
  95. #converts a VECTOR3D-struct to a tuple
  96. vec2tuple = lambda x: (x.x, x.y, x.z)
  97. #load vertices
  98. self.vertices = self._load_array(mesh.mVertices,
  99. mesh.mNumVertices,
  100. vec2tuple)
  101. #load normals
  102. self.normals = self._load_array(mesh.mNormals,
  103. mesh.mNumVertices,
  104. vec2tuple)
  105. #load tangents
  106. self.tangents = self._load_array(mesh.mTangents,
  107. mesh.mNumVertices,
  108. vec2tuple)
  109. #load bitangents
  110. self.bitangents = self._load_array(mesh.mBitangents,
  111. mesh.mNumVertices,
  112. vec2tuple)
  113. #vertex color sets
  114. self.colors = self._load_colors(mesh)
  115. #number of coordinates per uv-channel
  116. self.uvsize = self._load_uv_component_count(mesh)
  117. #number of uv channels
  118. self.texcoords = self._load_texture_coords(mesh)
  119. #the used material
  120. self.material_index = mesh.mMaterialIndex
  121. def _load_uv_component_count(self, mesh):
  122. """
  123. Loads the number of components for a given UV channel.
  124. mesh - mesh-data
  125. result (count channel 1, count channel 2, ...)
  126. """
  127. return tuple(mesh.mNumUVComponents[i]
  128. for i in range(structs.MESH.AI_MAX_NUMBER_OF_TEXTURECOORDS))
  129. def _load_texture_coords(self, mesh):
  130. """
  131. Loads texture coordinates.
  132. mesh - mesh-data
  133. result texture coordinates
  134. """
  135. result = []
  136. for i in range(structs.MESH.AI_MAX_NUMBER_OF_TEXTURECOORDS):
  137. result.append(self._load_array(mesh.mTextureCoords[i],
  138. mesh.mNumVertices,
  139. lambda x: (x.x, x.y, x.z)))
  140. return result
  141. def _load_colors(self, mesh):
  142. """
  143. Loads color sets.
  144. mesh - mesh with color sets
  145. result all color sets
  146. """
  147. result = []
  148. #for all possible sets
  149. for i in range(structs.MESH.AI_MAX_NUMBER_OF_COLOR_SETS):
  150. #try this set
  151. x = mesh.mColors[i]
  152. if x:
  153. channel = []
  154. #read data for al vertices!
  155. for j in range(mesh.mNumVertices):
  156. c = x[j]
  157. channel.append((c.r, c.g, c.b, c.a))
  158. result.append(channel)
  159. return result
  160. #the loader as singleton
  161. _assimp_lib = AssimpLib()
  162. def load(filename, processing=0):
  163. """
  164. Loads the model with some specific processing parameters.
  165. filename - file to load model from
  166. processing - processing parameters
  167. result Scene-object with model-data
  168. throws AssimpError - could not open file
  169. """
  170. #read pure data
  171. model = _assimp_lib.load(filename, processing)
  172. if not model:
  173. #Uhhh, something went wrong!
  174. raise AssimpError, ("could not import file: %s" % filename)
  175. try:
  176. #create scene
  177. return Scene(model.contents)
  178. finally:
  179. #forget raw data
  180. _assimp_lib.release(model)