move load_image into image_utils and add some docstrings to bpy_extras module.

This commit is contained in:
Campbell Barton
2011-05-28 09:34:45 +00:00
parent 245d36b706
commit a9dd90be78
5 changed files with 134 additions and 43 deletions

View File

@@ -65,8 +65,9 @@ else:
"bpy.props", "bpy.props",
"bpy.utils", "bpy.utils",
"bpy.context", "bpy.context",
# "bpy.types", # supports filtering "bpy.types", # supports filtering
"bpy.ops", # supports filtering "bpy.ops", # supports filtering
#"bpy_extras",
"bge", "bge",
"aud", "aud",
"bgl", "bgl",
@@ -363,10 +364,8 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
for submod_name in module_all: for submod_name in module_all:
ns = {} ns = {}
exec_str = "from %s import %s as submod" % (module.__name__, submod_name) exec_str = "from %s import %s as submod" % (module.__name__, submod_name)
print(exec_str)
exec(exec_str, ns, ns) exec(exec_str, ns, ns)
submod = ns["submod"] submod = ns["submod"]
print(submod)
if type(submod) == types.ModuleType: if type(submod) == types.ModuleType:
submod_ls.append((submod_name, submod)) submod_ls.append((submod_name, submod))

View File

@@ -19,19 +19,88 @@
# <pep8 compliant> # <pep8 compliant>
__all__ = ( __all__ = (
"image_load", "load_image",
) )
# limited replacement for BPyImage.comprehensiveImageLoad
def load_image(imagepath,
dirname="",
place_holder=False,
recursive=False,
ncase_cmp=True,
convert_callback=None,
verbose=False,
):
"""
Return an image from the file path with options to search multiple paths and
return a placeholder if its not found.
def image_load(filepath, dirpath, place_holder=False, recursive=False, convert_callback=None): :arg filepath: The image filename
import bpy If a path precedes it, this will be searched as well.
:type filepath: string
:arg dirname: is the directory where the image may be located - any file at
the end will be ignored.
:type dirname: string
:arg place_holder: if True a new place holder image will be created.
this is usefull so later you can relink the image to its original data.
:type place_holder: bool
:arg recursive: If True, directories will be recursivly searched.
Be carefull with this if you have files in your root directory because
it may take a long time.
:type recursive: bool
:arg ncase_cmp: on non windows systems, find the correct case for the file.
:type ncase_cmp: bool
:arg convert_callback: a function that takes an existing path and returns a new one.
Use this when loading image formats blender may not support, the CONVERT_CALLBACK
can take the path for a GIF (for example), convert it to a PNG and return the PNG's path.
For formats blender can read, simply return the path that is given.
:type convert_callback: function
:return: an image or None
:rtype: :class:`Image`
"""
import os import os
try: # TODO: recursive
return bpy.data.images.load(filepath)
except RuntimeError: def _image_load(path):
if place_holder: import bpy
image = bpy.data.images.new(os.path.basename(filepath), 128, 128)
# allow the path to be resolved later if convert_callback:
image.filepath = filepath path = convert_callback(path)
return image
image = bpy.data.images.load(path)
if verbose:
print(" image loaded '%s'" % path)
return image
if verbose:
print("load_image('%s', '%s', ...)" % (imagepath, dirname))
if os.path.exists(imagepath):
return _image_load(imagepath)
variants = [imagepath]
if dirname:
variants += [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
for filepath_test in variants:
if ncase_cmp:
ncase_variants = filepath_test, bpy.path.resolve_ncase(filepath)
else:
ncase_variants = (filepath_test, )
for nfilepath in ncase_variants:
if os.path.exists(nfilepath):
return _image_load(nfilepath)
if place_holder:
image = bpy.data.images.new(os.path.basename(filepath), 128, 128)
# allow the path to be resolved later
image.filepath = imagepath
return image
# TODO comprehensiveImageLoad also searched in bpy.config.textureDir
return None

View File

@@ -22,7 +22,6 @@ __all__ = (
"ExportHelper", "ExportHelper",
"ImportHelper", "ImportHelper",
"axis_conversion", "axis_conversion",
"load_image",
"create_derived_objects", "create_derived_objects",
"free_derived_objects", "free_derived_objects",
"unpack_list", "unpack_list",
@@ -162,24 +161,6 @@ def axis_conversion(from_forward='Y', from_up='Z', to_forward='Y', to_up='Z'):
assert("internal error") assert("internal error")
# limited replacement for BPyImage.comprehensiveImageLoad
def load_image(imagepath, dirname):
import os
if os.path.exists(imagepath):
return bpy.data.images.load(imagepath)
variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
for filepath in variants:
for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
if os.path.exists(nfilepath):
return bpy.data.images.load(nfilepath)
# TODO comprehensiveImageLoad also searched in bpy.config.textureDir
return None
# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() # return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
def create_derived_objects(scene, ob): def create_derived_objects(scene, ob):
if ob.parent and ob.parent.dupli_type != 'NONE': if ob.parent and ob.parent.dupli_type != 'NONE':

View File

@@ -28,11 +28,15 @@ __all__ = (
) )
def mesh_linked_faces(mesh): def mesh_linked_faces(mesh):
''' """
Splits the mesh into connected parts, Splits the mesh into connected faces, use this for seperating cubes from
these parts are returned as lists of faces. other mesh elements within 1 mesh datablock.
used for seperating cubes from other mesh elements in the 1 mesh
''' :arg mesh: the mesh used to group with.
:type mesh: :class:`Mesh`
:return: lists of lists containing faces.
:rtype: list
"""
# Build vert face connectivity # Build vert face connectivity
vert_faces = [[] for i in range(len(mesh.vertices))] vert_faces = [[] for i in range(len(mesh.vertices))]
@@ -78,6 +82,11 @@ def mesh_linked_faces(mesh):
def edge_face_count_dict(mesh): def edge_face_count_dict(mesh):
"""
:return: dict of edge keys with their value set to the number of
faces using each edge.
:rtype: dict
"""
face_edge_keys = [face.edge_keys for face in mesh.faces] face_edge_keys = [face.edge_keys for face in mesh.faces]
face_edge_count = {} face_edge_count = {}
for face_keys in face_edge_keys: for face_keys in face_edge_keys:
@@ -91,8 +100,13 @@ def edge_face_count_dict(mesh):
def edge_face_count(mesh): def edge_face_count(mesh):
"""
:return: list face users for each item in mesh.edges.
:rtype: list
"""
edge_face_count_dict = edge_face_count_dict(mesh) edge_face_count_dict = edge_face_count_dict(mesh)
return [edge_face_count_dict.get(ed.key, 0) for ed in mesh.edges] get = dict.get
return [get(edge_face_count_dict, ed.key, 0) for ed in mesh.edges]
def edge_loops_from_faces(mesh, faces=None, seams=()): def edge_loops_from_faces(mesh, faces=None, seams=()):
@@ -101,12 +115,18 @@ def edge_loops_from_faces(mesh, faces=None, seams=()):
Takes me.faces or a list of faces and returns the edge loops Takes me.faces or a list of faces and returns the edge loops
These edge loops are the edges that sit between quads, so they dont touch These edge loops are the edges that sit between quads, so they dont touch
1 quad, note: not connected will make 2 edge loops, both only containing 2 edges. 1 quad, note: not connected will make 2 edge loops,
both only containing 2 edges.
return a list of edge key lists return a list of edge key lists
[ [(0,1), (4, 8), (3,8)], ...] [[(0, 1), (4, 8), (3, 8)], ...]
return a list of edge vertex index lists :arg mesh: the mesh used to get edge loops from.
:type mesh: :class:`Mesh`
:arg faces: optional face list to only use some of the meshes faces.
:type faces: :class:`MeshFaces`, sequence or or NoneType
:return: return a list of edge vertex index lists.
:rtype: list
""" """
OTHER_INDEX = 2, 3, 0, 1 # opposite face index OTHER_INDEX = 2, 3, 0, 1 # opposite face index
@@ -117,7 +137,7 @@ def edge_loops_from_faces(mesh, faces=None, seams=()):
edges = {} edges = {}
for f in faces: for f in faces:
# if len(f) == 4: # if len(f) == 4:
if f.vertices_raw[3] != 0: if f.vertices_raw[3] != 0:
edge_keys = f.edge_keys edge_keys = f.edge_keys
for i, edkey in enumerate(f.edge_keys): for i, edkey in enumerate(f.edge_keys):

View File

@@ -29,6 +29,16 @@ import mathutils
def add_object_align_init(context, operator): def add_object_align_init(context, operator):
"""
Return a matrix using the operator settings and view context.
:arg context: The context to use.
:type context: :class:`Context`
:arg operator: The operator, checked for location and rotation properties.
:type operator: :class:`Operator`
:return: the matrix from the context and settings.
:rtype: :class:`Matrix`
"""
space_data = context.space_data space_data = context.space_data
if space_data.type != 'VIEW_3D': if space_data.type != 'VIEW_3D':
space_data = None space_data = None
@@ -70,7 +80,19 @@ def add_object_align_init(context, operator):
def object_data_add(context, obdata, operator=None): def object_data_add(context, obdata, operator=None):
"""
Add an object using the view context and preference to to initialize the
location, rotation and layer.
:arg context: The context to use.
:type context: :class:`Context`
:arg obdata: the data used for the new object.
:type obdata: valid object data type or None.
:arg operator: The operator, checked for location and rotation properties.
:type operator: :class:`Operator`
:return: the newly created object in the scene.
:rtype: :class:`ObjectBase`
"""
scene = context.scene scene = context.scene
# ugh, could be made nicer # ugh, could be made nicer