diff options
Diffstat (limited to 'release/scripts/modules/bpy_types.py')
-rw-r--r-- | release/scripts/modules/bpy_types.py | 207 |
1 files changed, 111 insertions, 96 deletions
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 84d05a7a48d..f7429474b06 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -23,6 +23,7 @@ import _bpy from mathutils import Vector StructRNA = bpy_types.Struct.__bases__[0] +StructMetaPropGroup = _bpy.StructMetaPropGroup # StructRNA = bpy_types.Struct @@ -141,19 +142,19 @@ class _GenericBone: def x_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector((1.0, 0.0, 0.0)) + return Vector((1.0, 0.0, 0.0)) * self.matrix.to_3x3() @property def y_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector((0.0, 1.0, 0.0)) + return Vector((0.0, 1.0, 0.0)) * self.matrix.to_3x3() @property def z_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0)) + return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() @property def basename(self): @@ -187,7 +188,7 @@ class _GenericBone: @length.setter def length(self, value): - self.tail = self.head + ((self.tail - self.head).normalize() * value) + self.tail = self.head + ((self.tail - self.head).normalized() * value) @property def vector(self): @@ -251,21 +252,21 @@ class _GenericBone: bones = id_data.pose.bones elif id_data_type == bpy_types.Armature: bones = id_data.edit_bones - if not bones: # not in editmode + if not bones: # not in editmode bones = id_data.bones return bones -class PoseBone(StructRNA, _GenericBone): +class PoseBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): __slots__ = () -class Bone(StructRNA, _GenericBone): +class Bone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): __slots__ = () -class EditBone(StructRNA, _GenericBone): +class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): __slots__ = () def align_orientation(self, other): @@ -277,19 +278,29 @@ class EditBone(StructRNA, _GenericBone): self.tail = self.head + vec self.roll = other.roll - def transform(self, matrix): + def transform(self, matrix, scale=True, roll=True): """ Transform the the bones head, tail, roll and envalope (when the matrix has a scale component). - Expects a 4x4 or 3x3 matrix. + + :arg matrix: 3x3 or 4x4 transformation matrix. + :type matrix: :class:`Matrix` + :arg scale: Scale the bone envalope by the matrix. + :type scale: bool + :arg roll: Correct the roll to point in the same relative direction to the head and tail. + :type roll: bool """ from mathutils import Vector - z_vec = self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0)) - self.tail = matrix * self.tail - self.head = matrix * self.head - scalar = matrix.median_scale - self.head_radius *= scalar - self.tail_radius *= scalar - self.align_roll(matrix * z_vec) + z_vec = Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() + self.tail = self.tail * matrix + self.head = self.head * matrix + + if scale: + scalar = matrix.median_scale + self.head_radius *= scalar + self.tail_radius *= scalar + + if roll: + self.align_roll(z_vec * matrix) def ord_ind(i1, i2): @@ -301,18 +312,25 @@ def ord_ind(i1, i2): class Mesh(bpy_types.ID): __slots__ = () - def from_pydata(self, verts, edges, faces): + def from_pydata(self, vertices, edges, faces): """ Make a mesh from a list of verts/edges/faces Until we have a nicer way to make geometry, use this. + + :arg vertices: float triplets each representing (X, Y, Z) eg: [(0.0, 1.0, 0.5), ...]. + :type vertices: iterable object + :arg edges: int pairs, each pair contains two indices to the *vertices* argument. eg: [(1, 2), ...] + :type edges: iterable object + :arg faces: iterator of faces, each faces contains three or four indices to the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...] + :type faces: iterable object """ - self.vertices.add(len(verts)) + self.vertices.add(len(vertices)) self.edges.add(len(edges)) self.faces.add(len(faces)) - verts_flat = [f for v in verts for f in v] - self.vertices.foreach_set("co", verts_flat) - del verts_flat + vertices_flat = [f for v in vertices for f in v] + self.vertices.foreach_set("co", vertices_flat) + del vertices_flat edges_flat = [i for e in edges for i in e] self.edges.foreach_set("vertices", edges_flat) @@ -325,7 +343,7 @@ class Mesh(bpy_types.ID): else: return f[0], f[1], f[2], 0 elif f[2] == 0 or f[3] == 0: - return f[3], f[0], f[1], f[2] + return f[2], f[3], f[0], f[1] return f faces_flat = [v for f in faces for v in treat_face(f)] @@ -368,7 +386,7 @@ class Mesh(bpy_types.ID): return a list of edge vertex index lists """ - OTHER_INDEX = 2, 3, 0, 1 # opposite face index + OTHER_INDEX = 2, 3, 0, 1 # opposite face index if faces is None: faces = self.faces @@ -389,7 +407,7 @@ class Mesh(bpy_types.ID): edge_loops = [] for edkey, ed_adj in edges.items(): - if 0 < len(ed_adj) < 3: # 1 or 2 + if 0 < len(ed_adj) < 3: # 1 or 2 # Seek the first edge context_loop = [edkey, ed_adj[0]] edge_loops.append(context_loop) @@ -407,11 +425,11 @@ class Mesh(bpy_types.ID): ed_adj = edges[context_loop[-1]] if len(ed_adj) != 2: - if other_dir and flipped == False: # the original edge had 2 other edges - flipped = True # only flip the list once + if other_dir and flipped == False: # the original edge had 2 other edges + flipped = True # only flip the list once context_loop.reverse() ed_adj[:] = [] - context_loop.append(other_dir) # save 1 lookiup + context_loop.append(other_dir) # save 1 lookiup ed_adj = edges[context_loop[-1]] if len(ed_adj) != 2: @@ -427,7 +445,6 @@ class Mesh(bpy_types.ID): # Dont look at this again ed_adj[:] = [] - return edge_loops def edge_loops_from_edges(self, edges=None): @@ -543,83 +560,38 @@ class Text(bpy_types.ID): import bpy return tuple(obj for obj in bpy.data.objects if self in [cont.text for cont in obj.game.controllers if cont.type == 'PYTHON']) -import collections - +# values are module: [(cls, path, line), ...] TypeMap = {} -# Properties (IDPropertyGroup) are different from types because they need to be registered -# before adding sub properties to them, so they are registered on definition -# and unregistered on unload -PropertiesMap = {} - -# Using our own loading function we set this to false -# so when running a script directly in the text editor -# registers moduals instantly. -_register_immediate = True - -def _unregister_module(module, free=True): - for t in TypeMap.get(module, ()): - try: - bpy_types.unregister(t) - except: - import traceback - print("bpy.utils._unregister_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__)) - traceback.print_exc() - - if free == True and module in TypeMap: - del TypeMap[module] - - - for t in PropertiesMap.get(module, ()): - try: - bpy_types.unregister(t) - except: - import traceback - print("bpy.utils._unload_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__)) - traceback.print_exc() - - if free == True and module in PropertiesMap: - del PropertiesMap[module] - - -def _register_module(module): - for t in TypeMap.get(module, ()): - try: - bpy_types.register(t) - except: - import traceback - print("bpy.utils._register_module(): Module '%s' failed to register class '%s.%s'" % (module, t.__module__, t.__name__)) - traceback.print_exc() class RNAMeta(type): - @classmethod - def _register_immediate(cls): - return _register_immediate - def __new__(cls, name, bases, classdict, **args): result = type.__new__(cls, name, bases, classdict) if bases and bases[0] != StructRNA: + import traceback + import weakref module = result.__module__ - ClassMap = TypeMap - - # Register right away if needed - if cls._register_immediate(): - bpy_types.register(result) - ClassMap = PropertiesMap - # first part of packages only if "." in module: module = module[:module.index(".")] - - ClassMap.setdefault(module, []).append(result) + + sf = traceback.extract_stack(limit=2)[0] + + TypeMap.setdefault(module, []).append((weakref.ref(result), sf[0], sf[1])) return result -class RNAMetaRegister(RNAMeta): - @classmethod - def _register_immediate(cls): - return True + @property + def is_registered(cls): + return "bl_rna" in cls.__dict__ + +import collections + + +class RNAMetaPropGroup(RNAMeta, StructMetaPropGroup): + pass + class OrderedMeta(RNAMeta): @@ -630,10 +602,39 @@ class OrderedMeta(RNAMeta): def __prepare__(name, bases, **kwargs): return collections.OrderedDict() + # Only defined so operators members can be used by accessing self.order +# with doc generation 'self.properties.bl_rna.properties' can fail class Operator(StructRNA, metaclass=OrderedMeta): __slots__ = () + def __getattribute__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if bl_rna and attr in bl_rna.properties: + return getattr(properties, attr) + return super().__getattribute__(attr) + + def __setattr__(self, attr, value): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if bl_rna and attr in bl_rna.properties: + return setattr(properties, attr, value) + return super().__setattr__(attr, value) + + def __delattr__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if bl_rna and attr in bl_rna.properties: + return delattr(properties, attr) + return super().__delattr__(attr) + + def as_keywords(self, ignore=()): + """ Return a copy of the properties as a dictionary. + """ + ignore = ignore + ("rna_type",) + return {attr: getattr(self, attr) for attr in self.properties.rna_type.properties.keys() if attr not in ignore} + class Macro(StructRNA, metaclass=OrderedMeta): # bpy_types is imported before ops is defined @@ -644,13 +645,20 @@ class Macro(StructRNA, metaclass=OrderedMeta): def define(self, opname): from _bpy import ops return ops.macro_define(self, opname) - -class IDPropertyGroup(StructRNA, metaclass=RNAMetaRegister): + + +class PropertyGroup(StructRNA, metaclass=RNAMetaPropGroup): __slots__ = () + class RenderEngine(StructRNA, metaclass=RNAMeta): __slots__ = () + +class KeyingSetInfo(StructRNA, metaclass=RNAMeta): + __slots__ = () + + class _GenericUI: __slots__ = () @@ -662,7 +670,12 @@ class _GenericUI: def draw_ls(self, context): for func in draw_ls._draw_funcs: - func(self, context) + # so bad menu functions dont stop the entire menu from drawing. + try: + func(self, context) + except: + import traceback + traceback.print_exc() draw_funcs = draw_ls._draw_funcs = [cls.draw] cls.draw = draw_ls @@ -671,7 +684,7 @@ class _GenericUI: @classmethod def append(cls, draw_func): - """Prepend an draw function to this menu, takes the same arguments as the menus draw function.""" + """Append a draw function to this menu, takes the same arguments as the menus draw function.""" draw_funcs = cls._dyn_ui_initialize() draw_funcs.append(draw_func) @@ -711,6 +724,9 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): layout = self.layout + if not searchpaths: + layout.label("* Missing Paths *") + # collect paths files = [] for directory in searchpaths: @@ -732,7 +748,6 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): props.filepath = filepath if operator == "script.execute_preset": props.menu_idname = self.bl_idname - props.preset_name = preset_name def draw_preset(self, context): """Define these on the subclass |