123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- #-*- coding: UTF-8 -*-
- """
- PyAssimp
- This is the main-module of PyAssimp.
- """
- import structs
- import ctypes
- import os
- from ctypes import POINTER, c_int, c_uint, c_double, c_char, c_float
- #get the assimp path
- LIBRARY = os.path.join(os.path.dirname(__file__), "assimp.so")
- class AssimpError(BaseException):
- """
- If ann internal error occures.
- """
- pass
- class AssimpLib(object):
- #open library
- _dll = ctypes.cdll.LoadLibrary(LIBRARY)
-
- #get functions
- load = _dll.aiImportFile
- load.restype = POINTER(structs.SCENE)
-
- release = _dll.aiReleaseImport
- class AssimpBase(object):
- """
- Base class for all Assimp-classes.
- """
-
- def _load_array(self, data, count, cons):
- """
- Loads a whole array out of data, and constructs a new object. If data
- is NULL, an empty list will be returned.
-
- data - pointer to array
- count - size of the array
- cons - constructor
-
- result array data
- """
- if data:
- return [cons(data[i]) for i in range(count)]
- else:
- return []
- class Scene(AssimpBase):
- """
- The root structure of the imported data.
- Everything that was imported from the given file can be accessed from here.
- """
-
- #possible flags
- FLAGS = {1 : "AI_SCENE_FLAGS_ANIM_SKELETON_ONLY"}
-
-
- def __init__(self, model):
- """
- Converts the model-data to a real scene
-
- model - the raw model-data
- """
- #process data
- self._load(model)
-
-
- def _load(self, model):
- """
- Converts model from raw-data to fancy data!
-
- model - pointer to data
- """
- #store scene flags
- self.flags = model.flags
-
- #load mesh-data
- self.meshes = self._load_array(model.mMeshes,
- model.mNumMeshes,
- lambda x: Mesh(x.contents))
-
-
- def list_flags(self):
- """
- Returns a list of all used flags.
-
- result list of flags
- """
- return [name for (key, value) in Scene.FLAGS.iteritems()
- if (key & self.flags)>0]
- class Mesh(AssimpBase):
- """
- A mesh represents a geometry or model with a single material.
- It usually consists of a number of vertices and a series of primitives/faces
- referencing the vertices. In addition there might be a series of bones, each
- of them addressing a number of vertices with a certain weight. Vertex data
- is presented in channels with each channel containing a single per-vertex
- information such as a set of texture coords or a normal vector.
- If a data pointer is non-null, the corresponding data stream is present.
-
- A Mesh uses only a single material which is referenced by a material ID.
- """
-
- def __init__(self, mesh):
- """
- Loads mesh from raw-data.
- """
- #process data
- self._load(mesh)
-
-
- def _load(self, mesh):
- """
- Loads mesh-data from raw data
-
- mesh - raw mesh-data
- """
- #converts a VECTOR3D-struct to a tuple
- vec2tuple = lambda x: (x.x, x.y, x.z)
-
- #load vertices
- self.vertices = self._load_array(mesh.mVertices,
- mesh.mNumVertices,
- vec2tuple)
-
- #load normals
- self.normals = self._load_array(mesh.mNormals,
- mesh.mNumVertices,
- vec2tuple)
-
- #load tangents
- self.tangents = self._load_array(mesh.mTangents,
- mesh.mNumVertices,
- vec2tuple)
-
- #load bitangents
- self.bitangents = self._load_array(mesh.mBitangents,
- mesh.mNumVertices,
- vec2tuple)
-
- #vertex color sets
- self.colors = self._load_colors(mesh)
-
- #number of coordinates per uv-channel
- self.uvsize = self._load_uv_component_count(mesh)
-
- #number of uv channels
- self.texcoords = self._load_texture_coords(mesh)
-
- #the used material
- self.material_index = mesh.mMaterialIndex
-
-
- def _load_uv_component_count(self, mesh):
- """
- Loads the number of components for a given UV channel.
-
- mesh - mesh-data
-
- result (count channel 1, count channel 2, ...)
- """
- return tuple(mesh.mNumUVComponents[i]
- for i in range(structs.MESH.AI_MAX_NUMBER_OF_TEXTURECOORDS))
-
-
- def _load_texture_coords(self, mesh):
- """
- Loads texture coordinates.
-
- mesh - mesh-data
-
- result texture coordinates
- """
- result = []
-
- for i in range(structs.MESH.AI_MAX_NUMBER_OF_TEXTURECOORDS):
- result.append(self._load_array(mesh.mTextureCoords[i],
- mesh.mNumVertices,
- lambda x: (x.x, x.y, x.z)))
-
- return result
-
-
- def _load_colors(self, mesh):
- """
- Loads color sets.
-
- mesh - mesh with color sets
-
- result all color sets
- """
- result = []
-
- #for all possible sets
- for i in range(structs.MESH.AI_MAX_NUMBER_OF_COLOR_SETS):
- #try this set
- x = mesh.mColors[i]
-
- if x:
- channel = []
-
- #read data for al vertices!
- for j in range(mesh.mNumVertices):
- c = x[j]
- channel.append((c.r, c.g, c.b, c.a))
-
- result.append(channel)
-
-
- return result
- #the loader as singleton
- _assimp_lib = AssimpLib()
- def load(filename, processing=0):
- """
- Loads the model with some specific processing parameters.
-
- filename - file to load model from
- processing - processing parameters
-
- result Scene-object with model-data
-
- throws AssimpError - could not open file
- """
- #read pure data
- model = _assimp_lib.load(filename, processing)
- if not model:
- #Uhhh, something went wrong!
- raise AssimpError, ("could not import file: %s" % filename)
-
- try:
- #create scene
- return Scene(model.contents)
- finally:
- #forget raw data
- _assimp_lib.release(model)
|