|
@@ -10,29 +10,20 @@ import sys
|
|
if sys.version_info < (2,6):
|
|
if sys.version_info < (2,6):
|
|
raise 'pyassimp: need python 2.6 or newer'
|
|
raise 'pyassimp: need python 2.6 or newer'
|
|
|
|
|
|
-
|
|
|
|
import ctypes
|
|
import ctypes
|
|
import os
|
|
import os
|
|
import numpy
|
|
import numpy
|
|
|
|
|
|
-import logging; logger = logging.getLogger("pyassimp")
|
|
|
|
-
|
|
|
|
-# Attach a default, null handler, to the logger.
|
|
|
|
-# applications can easily get log messages from pyassimp
|
|
|
|
-# by calling for instance
|
|
|
|
-# >>> logging.basicConfig(level=logging.DEBUG)
|
|
|
|
-# before importing pyassimp
|
|
|
|
-class NullHandler(logging.Handler):
|
|
|
|
- def emit(self, record):
|
|
|
|
- pass
|
|
|
|
-h = NullHandler()
|
|
|
|
-logger.addHandler(h)
|
|
|
|
|
|
+import logging
|
|
|
|
+logger = logging.getLogger("pyassimp")
|
|
|
|
+# attach default null handler to logger so it doesn't complain
|
|
|
|
+# even if you don't attach another handler to logger
|
|
|
|
+logger.addHandler(logging.NullHandler())
|
|
|
|
|
|
from . import structs
|
|
from . import structs
|
|
from .errors import AssimpError
|
|
from .errors import AssimpError
|
|
from . import helper
|
|
from . import helper
|
|
|
|
|
|
-
|
|
|
|
assimp_structs_as_tuple = (
|
|
assimp_structs_as_tuple = (
|
|
structs.Matrix4x4,
|
|
structs.Matrix4x4,
|
|
structs.Matrix3x3,
|
|
structs.Matrix3x3,
|
|
@@ -59,10 +50,9 @@ def make_tuple(ai_obj, type = None):
|
|
|
|
|
|
# It is faster and more correct to have an init function for each assimp class
|
|
# It is faster and more correct to have an init function for each assimp class
|
|
def _init_face(aiFace):
|
|
def _init_face(aiFace):
|
|
- aiFace.indices = [aiFace.mIndices[i] for i in range(aiFace.mNumIndices)]
|
|
|
|
|
|
+ aiFace.indices = [aiFace.mIndices[i] for i in xrange(aiFace.mNumIndices)]
|
|
|
|
|
|
-assimp_struct_inits = \
|
|
|
|
- { structs.Face : _init_face }
|
|
|
|
|
|
+assimp_struct_inits = { structs.Face : _init_face }
|
|
|
|
|
|
def call_init(obj, caller = None):
|
|
def call_init(obj, caller = None):
|
|
if helper.hasattr_silent(obj,'contents'): #pointer
|
|
if helper.hasattr_silent(obj,'contents'): #pointer
|
|
@@ -86,7 +76,7 @@ def _is_init_type(obj):
|
|
|
|
|
|
def _init(self, target = None, parent = None):
|
|
def _init(self, target = None, parent = None):
|
|
"""
|
|
"""
|
|
- Custom initialize() for C structs, adds safely accessable member functionality.
|
|
|
|
|
|
+ Custom initialize() for C structs, adds safely accessible member functionality.
|
|
|
|
|
|
:param target: set the object which receive the added methods. Useful when manipulating
|
|
:param target: set the object which receive the added methods. Useful when manipulating
|
|
pointers, to skip the intermediate 'contents' deferencing.
|
|
pointers, to skip the intermediate 'contents' deferencing.
|
|
@@ -214,7 +204,7 @@ class AssimpLib(object):
|
|
"""
|
|
"""
|
|
Assimp-Singleton
|
|
Assimp-Singleton
|
|
"""
|
|
"""
|
|
- load, release, dll = helper.search_library()
|
|
|
|
|
|
+ load, load_mem, release, dll = helper.search_library()
|
|
|
|
|
|
#the loader as singleton
|
|
#the loader as singleton
|
|
_assimp_lib = AssimpLib()
|
|
_assimp_lib = AssimpLib()
|
|
@@ -239,7 +229,6 @@ def pythonize_assimp(type, obj, scene):
|
|
return meshes
|
|
return meshes
|
|
|
|
|
|
if type == "ADDTRANSFORMATION":
|
|
if type == "ADDTRANSFORMATION":
|
|
-
|
|
|
|
def getnode(node, name):
|
|
def getnode(node, name):
|
|
if node.name == name: return node
|
|
if node.name == name: return node
|
|
for child in node.children:
|
|
for child in node.children:
|
|
@@ -251,51 +240,65 @@ def pythonize_assimp(type, obj, scene):
|
|
raise AssimpError("Object " + str(obj) + " has no associated node!")
|
|
raise AssimpError("Object " + str(obj) + " has no associated node!")
|
|
setattr(obj, "transformation", node.transformation)
|
|
setattr(obj, "transformation", node.transformation)
|
|
|
|
|
|
-
|
|
|
|
def recur_pythonize(node, scene):
|
|
def recur_pythonize(node, scene):
|
|
- """ Recursively call pythonize_assimp on
|
|
|
|
|
|
+ '''
|
|
|
|
+ Recursively call pythonize_assimp on
|
|
nodes tree to apply several post-processing to
|
|
nodes tree to apply several post-processing to
|
|
pythonize the assimp datastructures.
|
|
pythonize the assimp datastructures.
|
|
- """
|
|
|
|
-
|
|
|
|
|
|
+ '''
|
|
node.meshes = pythonize_assimp("MESH", node.meshes, scene)
|
|
node.meshes = pythonize_assimp("MESH", node.meshes, scene)
|
|
-
|
|
|
|
|
|
+
|
|
for mesh in node.meshes:
|
|
for mesh in node.meshes:
|
|
mesh.material = scene.materials[mesh.materialindex]
|
|
mesh.material = scene.materials[mesh.materialindex]
|
|
|
|
|
|
for cam in scene.cameras:
|
|
for cam in scene.cameras:
|
|
pythonize_assimp("ADDTRANSFORMATION", cam, scene)
|
|
pythonize_assimp("ADDTRANSFORMATION", cam, scene)
|
|
|
|
|
|
- #for light in scene.lights:
|
|
|
|
- # pythonize_assimp("ADDTRANSFORMATION", light, scene)
|
|
|
|
-
|
|
|
|
for c in node.children:
|
|
for c in node.children:
|
|
recur_pythonize(c, scene)
|
|
recur_pythonize(c, scene)
|
|
|
|
|
|
-
|
|
|
|
-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
|
|
|
|
- #from ctypes import c_char_p, c_uint
|
|
|
|
- #model = _assimp_lib.load(c_char_p(filename), c_uint(processing))
|
|
|
|
- model = _assimp_lib.load(filename.encode("ascii"), processing)
|
|
|
|
|
|
+def load(filename, processing=0, file_type=None):
|
|
|
|
+ '''
|
|
|
|
+ Load a model into a scene. On failure throws AssimpError.
|
|
|
|
+
|
|
|
|
+ Arguments
|
|
|
|
+ ---------
|
|
|
|
+ filename: Either a filename or a file object to load model from.
|
|
|
|
+ If a file object is passed, file_type MUST be specified
|
|
|
|
+ Otherwise Assimp has no idea which importer to use.
|
|
|
|
+ This is named 'filename' so as to not break legacy code.
|
|
|
|
+ processing: assimp processing parameters
|
|
|
|
+ file_type: string, such as 'stl'
|
|
|
|
+
|
|
|
|
+ Returns
|
|
|
|
+ ---------
|
|
|
|
+ Scene object with model-data
|
|
|
|
+ '''
|
|
|
|
+
|
|
|
|
+ if hasattr(filename, 'read'):
|
|
|
|
+ '''
|
|
|
|
+ This is the case where a file object has been passed to load.
|
|
|
|
+ It is calling the following function:
|
|
|
|
+ const aiScene* aiImportFileFromMemory(const char* pBuffer,
|
|
|
|
+ unsigned int pLength,
|
|
|
|
+ unsigned int pFlags,
|
|
|
|
+ const char* pHint)
|
|
|
|
+ '''
|
|
|
|
+ if file_type == None:
|
|
|
|
+ raise AssimpError('File type must be specified when passing file objects!')
|
|
|
|
+ data = filename.read()
|
|
|
|
+ model = _assimp_lib.load_mem(data,
|
|
|
|
+ len(data),
|
|
|
|
+ processing,
|
|
|
|
+ file_type)
|
|
|
|
+ else:
|
|
|
|
+ # a filename string has been passed
|
|
|
|
+ model = _assimp_lib.load(filename.encode("ascii"), processing)
|
|
|
|
+
|
|
if not model:
|
|
if not model:
|
|
- #Uhhh, something went wrong!
|
|
|
|
- raise AssimpError("could not import file: %s" % filename)
|
|
|
|
-
|
|
|
|
|
|
+ raise AssimpError('Could not import file!')
|
|
scene = _init(model.contents)
|
|
scene = _init(model.contents)
|
|
-
|
|
|
|
recur_pythonize(scene.rootnode, scene)
|
|
recur_pythonize(scene.rootnode, scene)
|
|
-
|
|
|
|
return scene
|
|
return scene
|
|
|
|
|
|
def release(scene):
|
|
def release(scene):
|