diff options
author | Xiao Xiangquan <xiaoxiangquan@gmail.com> | 2011-07-29 21:42:53 +0400 |
---|---|---|
committer | Xiao Xiangquan <xiaoxiangquan@gmail.com> | 2011-07-29 21:42:53 +0400 |
commit | 287b24926fefe078e4baae45808a5453b5c731bc (patch) | |
tree | e2336456d73c8b4bb5b9dad80cb475d5ea9c38d5 /release | |
parent | e382a373f5c26be3279ce91b119cce1b24bec388 (diff) | |
parent | b948459031dd6d0f1ccc81d607a589fd7d1e8ab2 (diff) |
merge with trunk r38787
Diffstat (limited to 'release')
33 files changed, 948 insertions, 372 deletions
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 07f1dc618dc..cf74282d064 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -31,6 +31,8 @@ __all__ = ( import bpy as _bpy +error_duplicates = False + def paths(): # RELEASE SCRIPTS: official scripts distributed in Blender releases paths = _bpy.utils.script_paths("addons") @@ -47,8 +49,11 @@ def paths(): def modules(module_cache): + global error_duplicates import os + error_duplicates = False + path_list = paths() # fake module importing @@ -117,7 +122,12 @@ def modules(module_cache): modules_stale -= {mod_name} mod = module_cache.get(mod_name) if mod: - if mod.__time__ != os.path.getmtime(mod_path): + if mod.__file__ != mod_path: + print("multiple addons with the same name:\n %r\n %r" % + (mod.__file__, mod_path)) + error_duplicates = True + + elif mod.__time__ != os.path.getmtime(mod_path): print("reloading addon:", mod_name, mod.__time__, os.path.getmtime(mod_path), mod_path) del module_cache[mod_name] mod = None diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index 5e95428f641..251fc947e94 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -117,7 +117,7 @@ def display_name_from_filepath(name): """ Returns the path stripped of directort and extension, ensured to be utf8 compatible. """ - return _os.path.splitext(_os.path.basename(name))[0].encode("utf8", "replace").decode("utf8") + return _os.path.splitext(basename(name))[0].encode("utf8", "replace").decode("utf8") def resolve_ncase(path): @@ -231,3 +231,12 @@ def module_names(path, recursive=False): modules.append(("%s.%s" % (filename, mod_name), mod_path)) return modules + + +def basename(path): + """ + Equivalent to os.path.basename, but skips a "//" suffix. + + Use for Windows compatibility. + """ + return _os.path.basename(path[2:] if path[:2] in {"//", b"//"} else path) diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 7c0d3d24cba..57d3e6dd703 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -298,11 +298,18 @@ _presets = _os.path.join(_scripts[0], "presets") # FIXME - multiple paths def preset_paths(subdir): """ Returns a list of paths for a specific preset. + + :arg subdir: preset subdirectory (must not be an absolute path). + :type subdir: string + :return: script paths. + :rtype: list """ dirs = [] for path in script_paths("presets", all=True): directory = _os.path.join(path, subdir) - if _os.path.isdir(directory): + if not directory.startswith(path): + raise Exception("invalid subdir given %r" % subdir) + elif _os.path.isdir(directory): dirs.append(directory) return dirs diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py index f91535a0ad4..e56c1c651c4 100644 --- a/release/scripts/modules/bpy_extras/image_utils.py +++ b/release/scripts/modules/bpy_extras/image_utils.py @@ -86,7 +86,9 @@ def load_image(imagepath, variants = [imagepath] if dirname: - variants += [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))] + variants += [os.path.join(dirname, imagepath), + os.path.join(dirname, bpy.path.basename(imagepath)), + ] for filepath_test in variants: if ncase_cmp: @@ -99,7 +101,7 @@ def load_image(imagepath, return _image_load(nfilepath) if place_holder: - image = bpy.data.images.new(os.path.basename(imagepath), 128, 128) + image = bpy.data.images.new(bpy.path.basename(imagepath), 128, 128) # allow the path to be resolved later image.filepath = imagepath return image diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index cfa2233f7b6..bd01897c639 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -22,6 +22,7 @@ __all__ = ( "ExportHelper", "ImportHelper", "axis_conversion", + "axis_conversion_ensure", "create_derived_objects", "free_derived_objects", "unpack_list", @@ -154,17 +155,55 @@ def axis_conversion(from_forward='Y', from_up='Z', to_forward='Y', to_up='Z'): if from_forward == to_forward and from_up == to_up: return Matrix().to_3x3() + if from_forward[-1] == from_up[-1] or to_forward[-1] == to_up[-1]: + raise Exception("invalid axis arguments passed, " + "can't use up/forward on the same axis.") + value = reduce(int.__or__, (_axis_convert_num[a] << (i * 3) for i, a in enumerate((from_forward, from_up, to_forward, to_up)))) for i, axis_lut in enumerate(_axis_convert_lut): if value in axis_lut: return Matrix(_axis_convert_matrix[i]) - assert("internal error") + assert(0) + + +def axis_conversion_ensure(operator, forward_attr, up_attr): + """ + Function to ensure an operator has valid axis conversion settings, intended + to be used from :class:`Operator.check`. + + :arg operator: the operator to access axis attributes from. + :type operator: :class:`Operator` + :arg forward_attr: + :type forward_attr: string + :arg up_attr: the directory the *filepath* will be referenced from (normally the export path). + :type up_attr: string + :return: True if the value was modified. + :rtype: boolean + """ + def validate(axis_forward, axis_up): + if axis_forward[-1] == axis_up[-1]: + axis_up = axis_up[0:-1] + 'XYZ'[('XYZ'.index(axis_up[-1]) + 1) % 3] + + return axis_forward, axis_up + + change = False + + axis = getattr(operator, forward_attr), getattr(operator, up_attr) + axis_new = validate(*axis) + + if axis != axis_new: + setattr(operator, forward_attr, axis_new[0]) + setattr(operator, up_attr, axis_new[1]) + + return True + else: + return False # 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): - if ob.parent and ob.parent.dupli_type != 'NONE': + if ob.parent and ob.parent.dupli_type in {'VERTS', 'FACES'}: return False, None if ob.dupli_type != 'NONE': diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index c0c0f9186bd..5796abce72c 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -50,11 +50,11 @@ def region_2d_to_vector_3d(region, rv3d, coord): -0.5 )) - w = (out[0] * persinv[0][3]) + \ - (out[1] * persinv[1][3]) + \ - (out[2] * persinv[2][3]) + persinv[3][3] + w = ((out[0] * persinv[0][3]) + + (out[1] * persinv[1][3]) + + (out[2] * persinv[2][3]) + persinv[3][3]) - return ((out * persinv) / w) - rv3d.view_matrix.inverted()[3].xyz + return ((persinv * out) / w) - rv3d.view_matrix.inverted()[3].xyz else: return rv3d.view_matrix.inverted()[2].xyz.normalized() @@ -116,7 +116,7 @@ def location_3d_to_region_2d(region, rv3d, coord): """ from mathutils import Vector - prj = Vector((coord[0], coord[1], coord[2], 1.0)) * rv3d.perspective_matrix + prj = rv3d.perspective_matrix * Vector((coord[0], coord[1], coord[2], 1.0)) if prj.w > 0.0: width_half = region.width / 2.0 height_half = region.height / 2.0 diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index f2cd46b20ae..8766c873dd8 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -144,21 +144,21 @@ class _GenericBone: """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((1.0, 0.0, 0.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((1.0, 0.0, 0.0)) @property def y_axis(self): """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((0.0, 1.0, 0.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((0.0, 1.0, 0.0)) @property def z_axis(self): """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((0.0, 0.0, 1.0)) @property def basename(self): @@ -294,9 +294,9 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): :type roll: bool """ from mathutils import Vector - z_vec = Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() - self.tail = self.tail * matrix - self.head = self.head * matrix + z_vec = self.matrix.to_3x3() * Vector((0.0, 0.0, 1.0)) + self.tail = matrix * self.tail + self.head = matrix * self.head if scale: scalar = matrix.median_scale @@ -304,7 +304,7 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): self.tail_radius *= scalar if roll: - self.align_roll(z_vec * matrix) + self.align_roll(matrix * z_vec) def ord_ind(i1, i2): diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 6ab803cc469..27a6d21d519 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy import mathutils @@ -40,8 +40,10 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): for minor_index in range(minor_seg): angle = 2 * pi * minor_index / minor_seg - vec = Vector((major_rad + (cos(angle) * minor_rad), 0.0, - (sin(angle) * minor_rad))) * quat + vec = quat * Vector((major_rad + (cos(angle) * minor_rad), + 0.0, + (sin(angle) * minor_rad), + )) verts.extend(vec[:]) @@ -72,7 +74,11 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): return verts, faces -from bpy.props import FloatProperty, IntProperty, BoolProperty, FloatVectorProperty +from bpy.props import (FloatProperty, + IntProperty, + BoolProperty, + FloatVectorProperty, + ) class AddTorus(bpy.types.Operator): @@ -82,7 +88,8 @@ class AddTorus(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} major_radius = FloatProperty(name="Major Radius", - description="Radius from the origin to the center of the cross sections", + description=("Radius from the origin to the " + "center of the cross sections"), default=1.0, min=0.01, max=100.0) minor_radius = FloatProperty(name="Minor Radius", description="Radius of the torus' cross section", diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 34c5b0d922a..a0267b8b947 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from bpy.props import StringProperty @@ -28,7 +28,11 @@ class EditExternally(bpy.types.Operator): bl_label = "Image Edit Externally" bl_options = {'REGISTER'} - filepath = StringProperty(name="File Path", description="Path to an image file", maxlen=1024, default="") + filepath = StringProperty( + name="File Path", + description="Path to an image file", + maxlen=1024, + ) def _editor_guess(self, context): import sys @@ -57,10 +61,13 @@ class EditExternally(bpy.types.Operator): def execute(self, context): import os import subprocess - filepath = bpy.path.abspath(self.filepath) + filepath = os.path.normpath(bpy.path.abspath(self.filepath)) if not os.path.exists(filepath): - self.report({'ERROR'}, "Image path %r not found, image may be packed or unsaved." % filepath) + self.report({'ERROR'}, + "Image path %r not found, image may be packed or " + "unsaved." % filepath) + return {'CANCELLED'} cmd = self._editor_guess(context) + [filepath] @@ -70,7 +77,10 @@ class EditExternally(bpy.types.Operator): except: import traceback traceback.print_exc() - self.report({'ERROR'}, "Image editor not found, please specify in User Preferences > File") + self.report({'ERROR'}, + "Image editor not found, " + "please specify in User Preferences > File") + return {'CANCELLED'} return {'FINISHED'} @@ -104,7 +114,9 @@ class SaveDirty(bpy.types.Operator): if "\\" not in filepath and "/" not in filepath: self.report({'WARNING'}, "Invalid path: " + filepath) elif filepath in unique_paths: - self.report({'WARNING'}, "Path used by more then one image: " + filepath) + self.report({'WARNING'}, + "Path used by more then one image: %r" % + filepath) else: unique_paths.add(filepath) image.save() @@ -144,12 +156,11 @@ class ProjectEdit(bpy.types.Operator): filepath = os.path.splitext(filepath)[0] # filepath = bpy.path.clean_name(filepath) # fixes <memory> rubbish, needs checking - if filepath.startswith(".") or filepath == "": - # TODO, have a way to check if the file is saved, assume startup.blend + if bpy.data.is_saved: + filepath = "//" + filepath + else: tmpdir = context.user_preferences.filepaths.temporary_directory filepath = os.path.join(tmpdir, "project_edit") - else: - filepath = "//" + filepath obj = context.object @@ -163,7 +174,7 @@ class ProjectEdit(bpy.types.Operator): filepath_final = filepath + ("%.3d.%s" % (i, EXT)) i += 1 - image_new.name = os.path.basename(filepath_final) + image_new.name = bpy.path.basename(filepath_final) ProjectEdit._proj_hack[0] = image_new.name image_new.filepath_raw = filepath_final # TODO, filepath raw is crummy diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 03b0e469310..344b238709f 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy @@ -111,7 +111,8 @@ class MeshMirrorUV(bpy.types.Operator): #for i, v in enumerate(mesh.vertices): vmap = {} - for mirror_a, mirror_b in (mirror_gt, mirror_lt), (mirror_lt, mirror_gt): + for mirror_a, mirror_b in ((mirror_gt, mirror_lt), + (mirror_lt, mirror_gt)): for co, i in mirror_a.items(): nco = (-co[0], co[1], co[2]) j = mirror_b.get(nco) @@ -120,7 +121,8 @@ class MeshMirrorUV(bpy.types.Operator): active_uv_layer = mesh.uv_textures.active.data fuvs = [(uv.uv1, uv.uv2, uv.uv3, uv.uv4) for uv in active_uv_layer] - fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) for uv in fuvs] + fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) + for uv in fuvs] # as a list faces = mesh.faces[:] diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 72e521be5cf..c0bd20b8910 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty @@ -29,9 +29,22 @@ class SelectPattern(bpy.types.Operator): bl_label = _("Select Pattern") bl_options = {'REGISTER', 'UNDO'} - pattern = StringProperty(name=_("Pattern"), description=_("Name filter using '*' and '?' wildcard chars"), maxlen=32, default="*") - case_sensitive = BoolProperty(name=_("Case Sensitive"), description=_("Do a case sensitive compare"), default=False) - extend = BoolProperty(name=_("Extend"), description=_("Extend the existing selection"), default=True) + pattern = StringProperty( + name=_("Pattern"), + description=_("Name filter using '*' and '?' wildcard chars"), + maxlen=32, + default="*", + ) + case_sensitive = BoolProperty( + name=_("Case Sensitive"), + description=_("Do a case sensitive compare"), + default=False, + ) + extend = BoolProperty( + name=_("Extend"), + description=_("Extend the existing selection"), + default=True, + ) def execute(self, context): @@ -40,22 +53,37 @@ class SelectPattern(bpy.types.Operator): if self.case_sensitive: pattern_match = fnmatch.fnmatchcase else: - pattern_match = lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper()) - + pattern_match = (lambda a, b: + fnmatch.fnmatchcase(a.upper(), b.upper())) + is_ebone = False obj = context.object if obj and obj.mode == 'POSE': items = obj.data.bones + if not self.extend: + bpy.ops.pose.select_all(action='DESELECT') elif obj and obj.type == 'ARMATURE' and obj.mode == 'EDIT': items = obj.data.edit_bones + if not self.extend: + bpy.ops.armature.select_all(action='DESELECT') + is_ebone = True else: items = context.visible_objects + if not self.extend: + bpy.ops.object.select_all(action='DESELECT') # Can be pose bones or objects for item in items: if pattern_match(item.name, self.pattern): item.select = True - elif not self.extend: - item.select = False + + # hrmf, perhaps there should be a utility function for this. + if is_ebone: + item.select_head = True + item.select_tail = True + if item.use_connect: + item_parent = item.parent + if item_parent is not None: + item_parent.select_tail = True return {'FINISHED'} @@ -94,19 +122,25 @@ class SelectCamera(bpy.types.Operator): class SelectHierarchy(bpy.types.Operator): - '''Select object relative to the active objects position in the hierarchy''' + '''Select object relative to the active objects position''' \ + '''in the hierarchy''' bl_idname = "object.select_hierarchy" bl_label = _("Select Hierarchy") bl_options = {'REGISTER', 'UNDO'} - direction = EnumProperty(items=( - ('PARENT', _("Parent"), ""), - ('CHILD', _("Child"), "")), - name=_("Direction"), - description=_("Direction to select in the hierarchy"), - default='PARENT') + direction = EnumProperty( + items=(('PARENT', _("Parent"), ""), + ('CHILD', _("Child"), "") + ), + name=_("Direction"), + description=_("Direction to select in the hierarchy"), + default='PARENT') - extend = BoolProperty(name=_("Extend"), description=_("Extend the existing selection"), default=False) + extend = BoolProperty( + name=_("Extend"), + description=_("Extend the existing selection"), + default=False, + ) @classmethod def poll(cls, context): @@ -164,7 +198,11 @@ class SubdivisionSet(bpy.types.Operator): level = IntProperty(name=_("Level"), default=1, min=-100, max=100, soft_min=-6, soft_max=6) - relative = BoolProperty(name=_("Relative"), description=_("Apply the subsurf level as an offset relative to the current level"), default=False) + relative = BoolProperty( + name=_("Relative"), + description=_("Apply the subsurf level as an offset relative to the current level"), + default=False, + ) @classmethod def poll(cls, context): @@ -216,7 +254,8 @@ class SubdivisionSet(bpy.types.Operator): mod = obj.modifiers.new("Subsurf", 'SUBSURF') mod.levels = level except: - self.report({'WARNING'}, "Modifiers cannot be added to object: " + obj.name) + self.report({'WARNING'}, + "Modifiers cannot be added to object: " + obj.name) for obj in context.selected_editable_objects: set_object_subd(obj) @@ -225,23 +264,36 @@ class SubdivisionSet(bpy.types.Operator): class ShapeTransfer(bpy.types.Operator): - '''Copy another selected objects active shape to this one by applying the relative offsets''' + '''Copy another selected objects active shape to this one by ''' \ + '''applying the relative offsets''' bl_idname = "object.shape_key_transfer" bl_label = _("Transfer Shape Key") bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty(items=( - ('OFFSET', _("Offset"), _("Apply the relative positional offset")), - ('RELATIVE_FACE', _("Relative Face"), _("Calculate the geometricly relative position (using faces).")), - ('RELATIVE_EDGE', _("Relative Edge"), _("Calculate the geometricly relative position (using edges)."))), - name=_("Transformation Mode"), - description=_("Method to apply relative shape positions to the new shape"), - default='OFFSET') - - use_clamp = BoolProperty(name=_("Clamp Offset"), - description=_("Clamp the transformation to the distance each vertex moves in the original shape."), - default=False) + mode = EnumProperty( + items=(('OFFSET', + _("Offset"), + _("Apply the relative positional offset") + ), + ('RELATIVE_FACE', + _("Relative Face"), + _("Calculate relative position (using faces)."), + ), + ('RELATIVE_EDGE', + _("Relative Edge"), + _("Calculate relative position (using edges)."), + ), + ), + name=_("Transformation Mode"), + description=_("Relative shape positions to the new shape method"), + default='OFFSET', + ) + use_clamp = BoolProperty( + name=_("Clamp Offset"), + description=_("Clamp the transformation to the distance each vertex moves in the original shape."), + default=False, + ) def _main(self, ob_act, objects, mode='OFFSET', use_clamp=False): @@ -273,13 +325,16 @@ class ShapeTransfer(bpy.types.Operator): orig_shape_coords = me_cos(ob_act.active_shape_key.data) orig_normals = me_nos(me.vertices) - # orig_coords = me_cos(me.vertices) # the actual mverts location isnt as relyable as the base shape :S + # the actual mverts location isnt as relyable as the base shape :S + # orig_coords = me_cos(me.vertices) orig_coords = me_cos(me.shape_keys.key_blocks[0].data) for ob_other in objects: me_other = ob_other.data if len(me_other.vertices) != len(me.vertices): - self.report({'WARNING'}, "Skipping '%s', vertex count differs" % ob_other.name) + self.report({'WARNING'}, + ("Skipping '%s', " + "vertex count differs") % ob_other.name) continue target_normals = me_nos(me_other.vertices) @@ -291,53 +346,90 @@ class ShapeTransfer(bpy.types.Operator): ob_add_shape(ob_other, orig_key_name) # editing the final coords, only list that stores wrapped coords - target_shape_coords = [v.co for v in ob_other.active_shape_key.data] + target_shape_coords = [v.co for v in + ob_other.active_shape_key.data] median_coords = [[] for i in range(len(me.vertices))] # Method 1, edge if mode == 'OFFSET': for i, vert_cos in enumerate(median_coords): - vert_cos.append(target_coords[i] + (orig_shape_coords[i] - orig_coords[i])) + vert_cos.append(target_coords[i] + + (orig_shape_coords[i] - orig_coords[i])) elif mode == 'RELATIVE_FACE': for face in me.faces: i1, i2, i3, i4 = face.vertices_raw if i4 != 0: pt = barycentric_transform(orig_shape_coords[i1], - orig_coords[i4], orig_coords[i1], orig_coords[i2], - target_coords[i4], target_coords[i1], target_coords[i2]) + orig_coords[i4], + orig_coords[i1], + orig_coords[i2], + target_coords[i4], + target_coords[i1], + target_coords[i2], + ) median_coords[i1].append(pt) pt = barycentric_transform(orig_shape_coords[i2], - orig_coords[i1], orig_coords[i2], orig_coords[i3], - target_coords[i1], target_coords[i2], target_coords[i3]) + orig_coords[i1], + orig_coords[i2], + orig_coords[i3], + target_coords[i1], + target_coords[i2], + target_coords[i3], + ) median_coords[i2].append(pt) pt = barycentric_transform(orig_shape_coords[i3], - orig_coords[i2], orig_coords[i3], orig_coords[i4], - target_coords[i2], target_coords[i3], target_coords[i4]) + orig_coords[i2], + orig_coords[i3], + orig_coords[i4], + target_coords[i2], + target_coords[i3], + target_coords[i4], + ) median_coords[i3].append(pt) pt = barycentric_transform(orig_shape_coords[i4], - orig_coords[i3], orig_coords[i4], orig_coords[i1], - target_coords[i3], target_coords[i4], target_coords[i1]) + orig_coords[i3], + orig_coords[i4], + orig_coords[i1], + target_coords[i3], + target_coords[i4], + target_coords[i1], + ) median_coords[i4].append(pt) else: pt = barycentric_transform(orig_shape_coords[i1], - orig_coords[i3], orig_coords[i1], orig_coords[i2], - target_coords[i3], target_coords[i1], target_coords[i2]) + orig_coords[i3], + orig_coords[i1], + orig_coords[i2], + target_coords[i3], + target_coords[i1], + target_coords[i2], + ) median_coords[i1].append(pt) pt = barycentric_transform(orig_shape_coords[i2], - orig_coords[i1], orig_coords[i2], orig_coords[i3], - target_coords[i1], target_coords[i2], target_coords[i3]) + orig_coords[i1], + orig_coords[i2], + orig_coords[i3], + target_coords[i1], + target_coords[i2], + target_coords[i3], + ) median_coords[i2].append(pt) pt = barycentric_transform(orig_shape_coords[i3], - orig_coords[i2], orig_coords[i3], orig_coords[i1], - target_coords[i2], target_coords[i3], target_coords[i1]) + orig_coords[i2], + orig_coords[i3], + orig_coords[i1], + target_coords[i2], + target_coords[i3], + target_coords[i1], + ) median_coords[i3].append(pt) elif mode == 'RELATIVE_EDGE': @@ -375,7 +467,8 @@ class ShapeTransfer(bpy.types.Operator): if use_clamp: # clamp to the same movement as the original # breaks copy between different scaled meshes. - len_from = (orig_shape_coords[i] - orig_coords[i]).length + len_from = (orig_shape_coords[i] - + orig_coords[i]).length ofs = co - target_coords[i] ofs.length = len_from co = target_coords[i] + ofs @@ -396,7 +489,10 @@ class ShapeTransfer(bpy.types.Operator): if 1: # swap from/to, means we cant copy to many at once. if len(objects) != 1: - self.report({'ERROR'}, "Expected one other selected mesh object to copy from") + self.report({'ERROR'}, + ("Expected one other selected " + "mesh object to copy from")) + return {'CANCELLED'} ob_act, objects = objects[0], [ob_act] @@ -430,11 +526,14 @@ class JoinUVs(bpy.types.Operator): bpy.ops.object.mode_set(mode='OBJECT', toggle=False) if not mesh.uv_textures: - self.report({'WARNING'}, "Object: %s, Mesh: '%s' has no UVs\n" % (obj.name, mesh.name)) + self.report({'WARNING'}, + "Object: %s, Mesh: '%s' has no UVs" + % (obj.name, mesh.name)) else: len_faces = len(mesh.faces) - uv_array = array.array('f', [0.0] * 8) * len_faces # seems to be the fastest way to create an array + # seems to be the fastest way to create an array + uv_array = array.array('f', [0.0] * 8) * len_faces mesh.uv_textures.active.data.foreach_get("uv_raw", uv_array) objects = context.selected_editable_objects[:] @@ -451,11 +550,18 @@ class JoinUVs(bpy.types.Operator): mesh_other.tag = True if len(mesh_other.faces) != len_faces: - self.report({'WARNING'}, "Object: %s, Mesh: '%s' has %d faces, expected %d\n" % (obj_other.name, mesh_other.name, len(mesh_other.faces), len_faces)) + self.report({'WARNING'}, "Object: %s, Mesh: " + "'%s' has %d faces, expected %d\n" + % (obj_other.name, + mesh_other.name, + len(mesh_other.faces), + len_faces), + ) else: uv_other = mesh_other.uv_textures.active if not uv_other: - uv_other = mesh_other.uv_textures.new() # should return the texture it adds + # should return the texture it adds + uv_other = mesh_other.uv_textures.new() # finally do the copy uv_other.data.foreach_set("uv_raw", uv_array) @@ -483,14 +589,18 @@ class MakeDupliFace(bpy.types.Operator): SCALE_FAC = 0.01 offset = 0.5 * SCALE_FAC - base_tri = Vector((-offset, -offset, 0.0)), Vector((offset, -offset, 0.0)), Vector((offset, offset, 0.0)), Vector((-offset, offset, 0.0)) + base_tri = (Vector((-offset, -offset, 0.0)), + Vector((+offset, -offset, 0.0)), + Vector((+offset, +offset, 0.0)), + Vector((-offset, +offset, 0.0)), + ) def matrix_to_quat(matrix): # scale = matrix.median_scale trans = matrix.to_translation() rot = matrix.to_3x3() # also contains scale - return [(b * rot) + trans for b in base_tri] + return [(rot * b) + trans for b in base_tri] scene = bpy.context.scene linked = {} for obj in bpy.context.selected_objects: @@ -499,7 +609,10 @@ class MakeDupliFace(bpy.types.Operator): linked.setdefault(data, []).append(obj) for data, objects in linked.items(): - face_verts = [axis for obj in objects for v in matrix_to_quat(obj.matrix_world) for axis in v] + face_verts = [axis for obj in objects + for v in matrix_to_quat(obj.matrix_world) + for axis in v] + faces = list(range(len(face_verts) // 3)) mesh = bpy.data.meshes.new(data.name + "_dupli") @@ -536,7 +649,8 @@ class MakeDupliFace(bpy.types.Operator): class IsolateTypeRender(bpy.types.Operator): - '''Hide unselected render objects of same type as active by setting the hide render flag''' + '''Hide unselected render objects of same type as active ''' \ + '''by setting the hide render flag''' bl_idname = "object.isolate_type_render" bl_label = _("Restrict Render Unselected") bl_options = {'REGISTER', 'UNDO'} diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index d662d292868..04a4d7d8f42 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -16,105 +16,211 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from mathutils import Vector from blf import gettext as _ +def GlobalBB_LQ(bb_world): -def align_objects(align_x, align_y, align_z, align_mode, relative_to): + # Initialize the variables with the 8th vertex + left, right, front, back, down, up = (bb_world[7][0], + bb_world[7][0], + bb_world[7][1], + bb_world[7][1], + bb_world[7][2], + bb_world[7][2], + ) + + # Test against the other 7 verts + for i in range (7): + + # X Range + val = bb_world[i][0] + if val < left: + left = val + + if val > right: + right = val + + # Y Range + val = bb_world[i][1] + if val < front: + front = val + + if val > back: + back = val + + # Z Range + val = bb_world[i][2] + if val < down: + down = val + + if val > up: + up = val + + return (Vector((left, front, up)), Vector((right, back, down))) + +def GlobalBB_HQ(obj): + + matrix_world = obj.matrix_world.copy() + + # Initialize the variables with the last vertex + + verts = obj.data.vertices + + val = matrix_world * verts[-1].co + + left, right, front, back, down, up = (val[0], + val[0], + val[1], + val[1], + val[2], + val[2], + ) + + # Test against all other verts + for i in range (len(verts)-1): + + vco = matrix_world * verts[i].co + + # X Range + val = vco[0] + if val < left: + left = val + + if val > right: + right = val + + # Y Range + val = vco[1] + if val < front: + front = val + + if val > back: + back = val + + # Z Range + val = vco[2] + if val < down: + down = val + + if val > up: + up = val + + return Vector((left, front, up)), Vector((right, back, down)) + + +def align_objects(align_x, + align_y, + align_z, + align_mode, + relative_to, + bb_quality): cursor = bpy.context.scene.cursor_location - Left_Up_Front_SEL = [0.0, 0.0, 0.0] - Right_Down_Back_SEL = [0.0, 0.0, 0.0] + Left_Front_Up_SEL = [0.0, 0.0, 0.0] + Right_Back_Down_SEL = [0.0, 0.0, 0.0] flag_first = True objs = [] for obj in bpy.context.selected_objects: - matrix_world = obj.matrix_world - bb_world = [Vector(v[:]) * matrix_world for v in obj.bound_box] + matrix_world = obj.matrix_world.copy() + bb_world = [matrix_world * Vector(v[:]) for v in obj.bound_box] objs.append((obj, bb_world)) if not objs: return False for obj, bb_world in objs: - Left_Up_Front = bb_world[1] - Right_Down_Back = bb_world[7] + + if bb_quality: + GBB = GlobalBB_HQ(obj) + else: + GBB = GlobalBB_LQ(bb_world) + + Left_Front_Up = GBB[0] + Right_Back_Down = GBB[1] # Active Center if obj == bpy.context.active_object: - center_active_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0 - center_active_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0 - center_active_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0 + center_active_x = (Left_Front_Up[0] + Right_Back_Down[0]) / 2.0 + center_active_y = (Left_Front_Up[1] + Right_Back_Down[1]) / 2.0 + center_active_z = (Left_Front_Up[2] + Right_Back_Down[2]) / 2.0 - size_active_x = (Right_Down_Back[0] - Left_Up_Front[0]) / 2.0 - size_active_y = (Right_Down_Back[1] - Left_Up_Front[1]) / 2.0 - size_active_z = (Left_Up_Front[2] - Right_Down_Back[2]) / 2.0 + size_active_x = (Right_Back_Down[0] - Left_Front_Up[0]) / 2.0 + size_active_y = (Right_Back_Down[1] - Left_Front_Up[1]) / 2.0 + size_active_z = (Left_Front_Up[2] - Right_Back_Down[2]) / 2.0 # Selection Center if flag_first: flag_first = False - Left_Up_Front_SEL[0] = Left_Up_Front[0] - Left_Up_Front_SEL[1] = Left_Up_Front[1] - Left_Up_Front_SEL[2] = Left_Up_Front[2] + Left_Front_Up_SEL[0] = Left_Front_Up[0] + Left_Front_Up_SEL[1] = Left_Front_Up[1] + Left_Front_Up_SEL[2] = Left_Front_Up[2] - Right_Down_Back_SEL[0] = Right_Down_Back[0] - Right_Down_Back_SEL[1] = Right_Down_Back[1] - Right_Down_Back_SEL[2] = Right_Down_Back[2] + Right_Back_Down_SEL[0] = Right_Back_Down[0] + Right_Back_Down_SEL[1] = Right_Back_Down[1] + Right_Back_Down_SEL[2] = Right_Back_Down[2] else: # X axis - if Left_Up_Front[0] < Left_Up_Front_SEL[0]: - Left_Up_Front_SEL[0] = Left_Up_Front[0] + if Left_Front_Up[0] < Left_Front_Up_SEL[0]: + Left_Front_Up_SEL[0] = Left_Front_Up[0] # Y axis - if Left_Up_Front[1] < Left_Up_Front_SEL[1]: - Left_Up_Front_SEL[1] = Left_Up_Front[1] + if Left_Front_Up[1] < Left_Front_Up_SEL[1]: + Left_Front_Up_SEL[1] = Left_Front_Up[1] # Z axis - if Left_Up_Front[2] > Left_Up_Front_SEL[2]: - Left_Up_Front_SEL[2] = Left_Up_Front[2] + if Left_Front_Up[2] > Left_Front_Up_SEL[2]: + Left_Front_Up_SEL[2] = Left_Front_Up[2] # X axis - if Right_Down_Back[0] > Right_Down_Back_SEL[0]: - Right_Down_Back_SEL[0] = Right_Down_Back[0] + if Right_Back_Down[0] > Right_Back_Down_SEL[0]: + Right_Back_Down_SEL[0] = Right_Back_Down[0] # Y axis - if Right_Down_Back[1] > Right_Down_Back_SEL[1]: - Right_Down_Back_SEL[1] = Right_Down_Back[1] + if Right_Back_Down[1] > Right_Back_Down_SEL[1]: + Right_Back_Down_SEL[1] = Right_Back_Down[1] # Z axis - if Right_Down_Back[2] < Right_Down_Back_SEL[2]: - Right_Down_Back_SEL[2] = Right_Down_Back[2] + if Right_Back_Down[2] < Right_Back_Down_SEL[2]: + Right_Back_Down_SEL[2] = Right_Back_Down[2] - center_sel_x = (Left_Up_Front_SEL[0] + Right_Down_Back_SEL[0]) / 2.0 - center_sel_y = (Left_Up_Front_SEL[1] + Right_Down_Back_SEL[1]) / 2.0 - center_sel_z = (Left_Up_Front_SEL[2] + Right_Down_Back_SEL[2]) / 2.0 + center_sel_x = (Left_Front_Up_SEL[0] + Right_Back_Down_SEL[0]) / 2.0 + center_sel_y = (Left_Front_Up_SEL[1] + Right_Back_Down_SEL[1]) / 2.0 + center_sel_z = (Left_Front_Up_SEL[2] + Right_Back_Down_SEL[2]) / 2.0 # Main Loop for obj, bb_world in objs: - bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] + matrix_world = obj.matrix_world.copy() + bb_world = [matrix_world * Vector(v[:]) for v in obj.bound_box] - Left_Up_Front = bb_world[1] - Right_Down_Back = bb_world[7] + if bb_quality: + GBB = GlobalBB_HQ(obj) + else: + GBB = GlobalBB_LQ(bb_world) + + Left_Front_Up = GBB[0] + Right_Back_Down = GBB[1] - center_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0 - center_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0 - center_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0 + center_x = (Left_Front_Up[0] + Right_Back_Down[0]) / 2.0 + center_y = (Left_Front_Up[1] + Right_Back_Down[1]) / 2.0 + center_z = (Left_Front_Up[2] + Right_Back_Down[2]) / 2.0 - positive_x = Right_Down_Back[0] - positive_y = Right_Down_Back[1] - positive_z = Left_Up_Front[2] + positive_x = Right_Back_Down[0] + positive_y = Right_Back_Down[1] + positive_z = Left_Front_Up[2] - negative_x = Left_Up_Front[0] - negative_y = Left_Up_Front[1] - negative_z = Right_Down_Back[2] + negative_x = Left_Front_Up[0] + negative_y = Left_Front_Up[1] + negative_z = Right_Back_Down[2] obj_loc = obj.location @@ -229,7 +335,7 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): return True -from bpy.props import EnumProperty +from bpy.props import EnumProperty, BoolProperty class AlignObjects(bpy.types.Operator): @@ -238,6 +344,11 @@ class AlignObjects(bpy.types.Operator): bl_label = _("Align Objects") bl_options = {'REGISTER', 'UNDO'} + bb_quality = BoolProperty( + name=_("High Quality"), + description=_("Enables high quality calculation of the bounding box for perfect results on complex shape meshes with rotation/scale (Slow)"), + default=True) + align_mode = EnumProperty(items=( ('OPT_1', "Negative Sides", ""), ('OPT_2', "Centers", ""), @@ -270,7 +381,12 @@ class AlignObjects(bpy.types.Operator): def execute(self, context): align_axis = self.align_axis - ret = align_objects('X' in align_axis, 'Y' in align_axis, 'Z' in align_axis, self.align_mode, self.relative_to) + ret = align_objects('X' in align_axis, + 'Y' in align_axis, + 'Z' in align_axis, + self.align_mode, + self.relative_to, + self.bb_quality) if not ret: self.report({'WARNING'}, "No objects with bound-box selected") diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 074f204d50e..ba739648000 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -16,12 +16,17 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> from mathutils import Vector import bpy -from bpy.props import BoolProperty, EnumProperty, IntProperty, FloatProperty, FloatVectorProperty - +from bpy.props import (BoolProperty, + EnumProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + ) +from blf import gettext as _ def object_ensure_material(obj, mat_name): """ Use an existing material or add a new one. @@ -61,7 +66,8 @@ class QuickFur(bpy.types.Operator): def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] + mesh_objects = [obj for obj in context.selected_objects + if obj.type == 'MESH'] if not mesh_objects: self.report({'ERROR'}, "Select at least one mesh object.") @@ -92,7 +98,8 @@ class QuickFur(bpy.types.Operator): psys.settings.child_type = 'INTERPOLATED' obj.data.materials.append(mat) - obj.particle_systems[-1].settings.material = len(obj.data.materials) + obj.particle_systems[-1].settings.material = \ + len(obj.data.materials) return {'FINISHED'} @@ -149,7 +156,10 @@ class QuickExplode(bpy.types.Operator): for obj in mesh_objects: if obj.particle_systems: - self.report({'ERROR'}, "Object %r already has a particle system" % obj.name) + self.report({'ERROR'}, + "Object %r already has a " + "particle system" % obj.name) + return {'CANCELLED'} if self.fade: @@ -184,9 +194,7 @@ class QuickExplode(bpy.types.Operator): if self.fade: explode.show_dead = False - bpy.ops.mesh.uv_texture_add(fake_context) - uv = obj.data.uv_textures[-1] - uv.name = "Explode fade" + uv = obj.data.uv_textures.new("Explode fade") explode.particle_uv = uv.name mat = object_ensure_material(obj, "Explode Fade") @@ -247,7 +255,7 @@ class QuickExplode(bpy.types.Operator): def obj_bb_minmax(obj, min_co, max_co): for i in range(0, 8): - bb_vec = Vector(obj.bound_box[i]) * obj.matrix_world + bb_vec = obj.matrix_world * Vector(obj.bound_box[i]) min_co[0] = min(bb_vec[0], min_co[0]) min_co[1] = min(bb_vec[1], min_co[1]) @@ -262,21 +270,26 @@ class QuickSmoke(bpy.types.Operator): bl_label = "Quick Smoke" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty(items=( - ('STREAM', "Stream", ""), - ('PUFF', "Puff", ""), - ('FIRE', "Fire", "")), - name="Smoke Style", - description="", - default='STREAM') - - show_flows = BoolProperty(name="Render Smoke Objects", - description="Keep the smoke objects visible during rendering.", - default=False) + style = EnumProperty( + items=(('STREAM', "Stream", ""), + ('PUFF', "Puff", ""), + ('FIRE', "Fire", ""), + ), + name="Smoke Style", + description="", + default='STREAM', + ) + + show_flows = BoolProperty( + name=_("Render Smoke Objects"), + description=_("Keep the smoke objects visible during rendering."), + default=False, + ) def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] + mesh_objects = [obj for obj in context.selected_objects + if obj.type == 'MESH'] min_co = Vector((100000.0, 100000.0, 100000.0)) max_co = -min_co @@ -336,21 +349,25 @@ class QuickSmoke(bpy.types.Operator): mat.volume.density = 0 mat.volume.density_scale = 5 - mat.texture_slots.add() - mat.texture_slots[0].texture = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA') - mat.texture_slots[0].texture.voxel_data.domain_object = obj - mat.texture_slots[0].use_map_color_emission = False - mat.texture_slots[0].use_map_density = True + tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA') + tex.voxel_data.domain_object = obj + + tex_slot = mat.texture_slots.add() + tex_slot.texture = tex + tex_slot.use_map_color_emission = False + tex_slot.use_map_density = True # for fire add a second texture for emission and emission color if self.style == 'FIRE': mat.volume.emission = 5 - mat.texture_slots.add() - mat.texture_slots[1].texture = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA') - mat.texture_slots[1].texture.voxel_data.domain_object = obj - mat.texture_slots[1].texture.use_color_ramp = True + tex = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA') + tex.voxel_data.domain_object = obj + tex.use_color_ramp = True + + tex_slot = mat.texture_slots.add() + tex_slot.texture = tex - ramp = mat.texture_slots[1].texture.color_ramp + ramp = tex.color_ramp elem = ramp.elements.new(0.333) elem.color[0] = elem.color[3] = 1 @@ -371,28 +388,37 @@ class QuickFluid(bpy.types.Operator): bl_label = "Quick Fluid" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty(items=( - ('INFLOW', "Inflow", ""), - ('BASIC', "Basic", "")), + style = EnumProperty( + items=(('INFLOW', "Inflow", ""), + ('BASIC', "Basic", ""), + ), name="Fluid Style", description="", - default='BASIC') - - initial_velocity = FloatVectorProperty(name="Initial Velocity", - description="Initial velocity of the fluid", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='VELOCITY') - - show_flows = BoolProperty(name="Render Fluid Objects", - description="Keep the fluid objects visible during rendering.", - default=False) - - start_baking = BoolProperty(name="Start Fluid Bake", - description="Start baking the fluid immediately after creating the domain object.", - default=False) + default='BASIC', + ) + initial_velocity = FloatVectorProperty( + name=_("Initial Velocity"), + description=_("Initial velocity of the fluid"), + default=(0.0, 0.0, 0.0), + min=-100.0, + max=100.0, + subtype='VELOCITY', + ) + show_flows = BoolProperty( + name=_("Render Fluid Objects"), + description=_("Keep the fluid objects visible during rendering."), + default=False, + ) + start_baking = BoolProperty( + name=_("Start Fluid Bake"), + description=_("Start baking the fluid immediately after creating the domain object"), + default=False, + ) def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if (obj.type == 'MESH' and not 0 in obj.dimensions)] + mesh_objects = [obj for obj in context.selected_objects + if (obj.type == 'MESH' and not 0.0 in obj.dimensions)] min_co = Vector((100000, 100000, 100000)) max_co = Vector((-100000, -100000, -100000)) @@ -405,7 +431,8 @@ class QuickFluid(bpy.types.Operator): # make each selected object a fluid bpy.ops.object.modifier_add(fake_context, type='FLUID_SIMULATION') - # fluid has to be before constructive modifiers, so it might not be the last modifier + # fluid has to be before constructive modifiers, + # so it might not be the last modifier for mod in obj.modifiers: if mod.type == 'FLUID_SIMULATION': break @@ -429,10 +456,14 @@ class QuickFluid(bpy.types.Operator): obj = context.active_object obj.name = "Fluid Domain" - # give the fluid some room below the flows and scale with initial velocity + # give the fluid some room below the flows + # and scale with initial velocity v = 0.5 * self.initial_velocity obj.location = 0.5 * (max_co + min_co) + Vector((0.0, 0.0, -1.0)) + v - obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0)) + Vector((abs(v[0]), abs(v[1]), abs(v[2]))) + obj.scale = (0.5 * (max_co - min_co) + + Vector((1.0, 1.0, 2.0)) + + Vector((abs(v[0]), abs(v[1]), abs(v[2]))) + ) # setup smoke domain bpy.ops.object.modifier_add(type='FLUID_SIMULATION') diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index d95a21cca81..acb988e147a 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from blf import gettext as _ @@ -94,40 +94,67 @@ class RandomizeLocRotSize(bpy.types.Operator): bl_label = _("Randomize Transform") bl_options = {'REGISTER', 'UNDO'} - random_seed = IntProperty(name="Random Seed", - description="Seed value for the random generator", - default=0, min=0, max=1000) - - use_delta = BoolProperty(name="Transform Delta", - description="Randomize delta transform values instead of regular transform", default=False) - - use_loc = BoolProperty(name="Randomize Location", - description="Randomize the location values", default=True) - - loc = FloatVectorProperty(name="Location", - description="Maximun distance the objects can spread over each axis", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='TRANSLATION') - - use_rot = BoolProperty(name="Randomize Rotation", - description="Randomize the rotation values", default=True) - - rot = FloatVectorProperty(name="Rotation", - description="Maximun rotation over each axis", - default=(0.0, 0.0, 0.0), min=-180.0, max=180.0, subtype='TRANSLATION') - - use_scale = BoolProperty(name="Randomize Scale", - description="Randomize the scale values", default=True) - - scale_even = BoolProperty(name="Scale Even", - description="Use the same scale value for all axis", default=False) + random_seed = IntProperty( + name=_("Random Seed"), + description=_("Seed value for the random generator"), + min=0, + max=1000, + default=0, + ) + use_delta = BoolProperty( + name=_("Transform Delta"), + description=_("Randomize delta transform values instead of regular transform"), + default=False, + ) + use_loc = BoolProperty( + name=_("Randomize Location"), + description=_("Randomize the location values"), + default=True, + ) + loc = FloatVectorProperty( + name=_("Location"), + description=_("Maximun distance the objects can spread over each axis"), + min=-100.0, + max=100.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) + use_rot = BoolProperty( + name=_("Randomize Rotation"), + description=_("Randomize the rotation values"), + default=True, + ) + rot = FloatVectorProperty( + name=_("Rotation"), + description=_("Maximun rotation over each axis"), + min=-180.0, + max=180.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) + use_scale = BoolProperty( + name=_("Randomize Scale"), + description=_("Randomize the scale values"), + default=True, + ) + scale_even = BoolProperty( + name=_("Scale Even"), + description=_("Use the same scale value for all axis"), + default=False, + ) '''scale_min = FloatProperty(name="Minimun Scale Factor", description="Lowest scale percentage possible", default=0.15, min=-1.0, max=1.0, precision=3)''' - scale = FloatVectorProperty(name="Scale", - description="Maximum scale randomization over each axis", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='TRANSLATION') + scale = FloatVectorProperty( + name=_("Scale"), + description=_("Maximum scale randomization over each axis"), + min=-100.0, + max=100.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) def execute(self, context): from math import radians diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 6624c2ad288..31a6f421768 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from blf import gettext as _ @@ -31,8 +31,15 @@ class AddPresetBase(): # bl_label = "Add a Python Preset" bl_options = {'REGISTER'} # only because invoke_props_popup requires. - name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="") - remove_active = bpy.props.BoolProperty(default=False, options={'HIDDEN'}) + name = bpy.props.StringProperty( + name=_("Name"), + description=_("Name of the preset, used to make the path name"), + maxlen=64, + ) + remove_active = bpy.props.BoolProperty( + default=False, + options={'HIDDEN'}, + ) @staticmethod def as_filename(name): # could reuse for other presets @@ -55,7 +62,10 @@ class AddPresetBase(): filename = self.as_filename(name) - target_path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", self.preset_subdir), create=True) + target_path = os.path.join("presets", self.preset_subdir) + target_path = bpy.utils.user_resource('SCRIPTS', + target_path, + create=True) if not target_path: self.report({'WARNING'}, "Failed to create presets path") @@ -96,7 +106,9 @@ class AddPresetBase(): filepath = bpy.utils.preset_find(preset_active, self.preset_subdir) if not filepath: - filepath = bpy.utils.preset_find(preset_active, self.preset_subdir, display_name=True) + filepath = bpy.utils.preset_find(preset_active, + self.preset_subdir, + display_name=True) if not filepath: return {'CANCELLED'} @@ -132,10 +144,17 @@ class AddPresetBase(): class ExecutePreset(bpy.types.Operator): ''' Executes a preset ''' bl_idname = "script.execute_preset" - bl_label = "Execute a Python Preset" - - filepath = bpy.props.StringProperty(name="Path", description="Path of the Python file to execute", maxlen=512, default="") - menu_idname = bpy.props.StringProperty(name="Menu ID Name", description="ID name of the menu this was called from", default="") + bl_label = _("Execute a Python Preset") + + filepath = bpy.props.StringProperty( + name=_("Path"), + description=_("Path of the Python file to execute"), + maxlen=512, + ) + menu_idname = bpy.props.StringProperty( + name=_("Menu ID Name"), + description=_("ID name of the menu this was called from"), + ) def execute(self, context): from os.path import basename @@ -153,7 +172,7 @@ class ExecutePreset(bpy.types.Operator): class AddPresetRender(AddPresetBase, bpy.types.Operator): '''Add a Render Preset''' bl_idname = "render.preset_add" - bl_label = "Add Render Preset" + bl_label = _("Add Render Preset") preset_menu = "RENDER_MT_presets" preset_defines = [ @@ -179,11 +198,14 @@ class AddPresetRender(AddPresetBase, bpy.types.Operator): class AddPresetSSS(AddPresetBase, bpy.types.Operator): '''Add a Subsurface Scattering Preset''' bl_idname = "material.sss_preset_add" - bl_label = "Add SSS Preset" + bl_label = _("Add SSS Preset") preset_menu = "MATERIAL_MT_sss_presets" preset_defines = [ - "material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)" + ("material = " + "bpy.context.material.active_node_material " + "if bpy.context.material.active_node_material " + "else bpy.context.material") ] preset_values = [ @@ -204,7 +226,7 @@ class AddPresetSSS(AddPresetBase, bpy.types.Operator): class AddPresetCloth(AddPresetBase, bpy.types.Operator): '''Add a Cloth Preset''' bl_idname = "cloth.preset_add" - bl_label = "Add Cloth Preset" + bl_label = _("Add Cloth Preset") preset_menu = "CLOTH_MT_presets" preset_defines = [ @@ -226,7 +248,7 @@ class AddPresetCloth(AddPresetBase, bpy.types.Operator): class AddPresetSunSky(AddPresetBase, bpy.types.Operator): '''Add a Sky & Atmosphere Preset''' bl_idname = "lamp.sunsky_preset_add" - bl_label = "Add Sunsky Preset" + bl_label = _("Add Sunsky Preset") preset_menu = "LAMP_MT_sunsky_presets" preset_defines = [ @@ -282,7 +304,7 @@ class AddPresetInteraction(AddPresetBase, bpy.types.Operator): class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator): '''Add a Keyconfig Preset''' bl_idname = "wm.keyconfig_preset_add" - bl_label = "Add Keyconfig Preset" + bl_label = _("Add Keyconfig Preset") preset_menu = "USERPREF_MT_keyconfigs" preset_subdir = "keyconfig" __doc__ = _('Add a Keyconfig Preset') @@ -310,7 +332,11 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): preset_menu = "WM_MT_operator_presets" __doc__ = _("Add an Application Interaction Preset") - operator = bpy.props.StringProperty(name="Operator", maxlen=64, options={'HIDDEN'}) + operator = bpy.props.StringProperty( + name=_("Operator"), + maxlen=64, + options={'HIDDEN'}, + ) # XXX, not ideal preset_defines = [ @@ -326,12 +352,15 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): properties_blacklist = bpy.types.Operator.bl_rna.properties.keys() prefix, suffix = self.operator.split("_OT_", 1) - operator_rna = getattr(getattr(bpy.ops, prefix.lower()), suffix).get_rna().bl_rna + op = getattr(getattr(bpy.ops, prefix.lower()), suffix) + operator_rna = op.get_rna().bl_rna + del op ret = [] for prop_id, prop in operator_rna.properties.items(): - if (not (prop.is_hidden or prop.is_skip_save)) and prop_id not in properties_blacklist: - ret.append("op.%s" % prop_id) + if not (prop.is_hidden or prop.is_skip_save): + if prop_id not in properties_blacklist: + ret.append("op.%s" % prop_id) return ret @@ -343,7 +372,7 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): class WM_MT_operator_presets(bpy.types.Menu): - bl_label = "Operator Presets" + bl_label = _("Operator Presets") def draw(self, context): self.operator = context.space_data.operator.bl_idname diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 2406cc59952..ba0b1da45d1 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -1,27 +1,23 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** +# ##### BEGIN GPL LICENSE BLOCK ##### # -# Script copyright (C) Campbell J Barton +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. # -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** +# ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> -# History -# # Originally written by Matt Ebb import bpy @@ -47,8 +43,10 @@ def guess_player_path(preset): player_path = "djv_view" if sys.platform == "darwin": - # TODO, crummy supporting only 1 version, could find the newest installed version - test_path = '/Applications/djv-0.8.2.app/Contents/Resources/bin/djv_view' + # TODO, crummy supporting only 1 version, + # could find the newest installed version + test_path = ("/Applications/djv-0.8.2.app" + "/Contents/Resources/bin/djv_view") if os.path.exists(test_path): player_path = test_path @@ -61,6 +59,9 @@ def guess_player_path(preset): elif preset == 'MPLAYER': player_path = "mplayer" + else: + player_path = "" + return player_path @@ -84,10 +85,10 @@ class PlayRenderedAnim(bpy.types.Operator): is_movie = rd.is_movie_format # try and guess a command line if it doesn't exist - if player_path == '': + if player_path == "": player_path = guess_player_path(preset) - if is_movie == False and preset in ('FRAMECYCLER', 'RV', 'MPLAYER'): + if is_movie == False and preset in {'FRAMECYCLER', 'RV', 'MPLAYER'}: # replace the number with '#' file_a = rd.frame_path(frame=0) @@ -97,11 +98,11 @@ class PlayRenderedAnim(bpy.types.Operator): while len(file_a) == len(file_b): frame_tmp = (frame_tmp * 10) + 9 - print(frame_tmp) file_b = rd.frame_path(frame=frame_tmp) file_b = rd.frame_path(frame=int(frame_tmp / 10)) - file = "".join((c if file_b[i] == c else "#") for i, c in enumerate(file_a)) + file = ("".join((c if file_b[i] == c else "#") + for i, c in enumerate(file_a))) else: # works for movies and images file = rd.frame_path(frame=scene.frame_start) @@ -111,10 +112,35 @@ class PlayRenderedAnim(bpy.types.Operator): cmd = [player_path] # extra options, fps controls etc. if preset == 'BLENDER24': + # ----------------------------------------------------------------- + # Check blender is not 2.5x until it supports playback again + try: + process = subprocess.Popen([player_path, '--version'], + stdout=subprocess.PIPE, + ) + except: + # ignore and allow the main execution to catch the problem. + process = None + + if process is not None: + process.wait() + out = process.stdout.read() + process.stdout.close() + out_split = out.strip().split() + if out_split[0] == b'Blender': + if not out_split[1].startswith(b'2.4'): + self.report({'ERROR'}, + "Blender %s doesn't support playback: %r" % + (out_split[1].decode(), player_path)) + return {'CANCELLED'} + del out, out_split + del process + # ----------------------------------------------------------------- + opts = ["-a", "-f", str(rd.fps), str(rd.fps_base), file] cmd.extend(opts) elif preset == 'DJV': - opts = [file, "-playback_speed", str(rd.fps)] + opts = [file, "-playback_speed", "%d" % int(rd.fps / rd.fps_base)] cmd.extend(opts) elif preset == 'FRAMECYCLER': opts = [file, "%d-%d" % (scene.frame_start, scene.frame_end)] @@ -127,18 +153,26 @@ class PlayRenderedAnim(bpy.types.Operator): if is_movie: opts.append(file) else: - opts.append("mf://%s" % file.replace("#", "?")) - opts += ["-mf", "fps=%.4f" % (rd.fps / rd.fps_base)] + opts += [("mf://%s" % file.replace("#", "?")), + "-mf", + "fps=%.4f" % (rd.fps / rd.fps_base), + ] + opts += ["-loop", "0", "-really-quiet", "-fs"] cmd.extend(opts) else: # 'CUSTOM' cmd.append(file) # launch it + print("Executing command:\n %r" % " ".join(cmd)) + try: process = subprocess.Popen(cmd) - except: - pass - #raise OSError("Couldn't find an external animation player.") + except Exception as e: + import traceback + self.report({'ERROR'}, + "Couldn't run external animation player with command " + "%r\n%s" % (" ".join(cmd), str(e))) + return {'CANCELLED'} return {'FINISHED'} diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 7ea89cfa479..851f33bde11 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -243,7 +243,7 @@ def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1): # Do this allong the way if mat != -1: - v = vecs[i] = v*mat + v = vecs[i] = mat * v x= v.x y= v.y if x<minx: minx= x @@ -747,14 +747,8 @@ def packIslands(islandList): def VectoQuat(vec): - a3 = vec.normalized() - up = Vector((0.0, 0.0, 1.0)) - if abs(a3.dot(up)) == 1.0: - up = Vector((0.0, 1.0, 0.0)) - - a1 = a3.cross(up).normalized() - a2 = a3.cross(a1) - return Matrix((a1, a2, a3)).to_quaternion() + vec = vec.normalized() + return vec.to_track_quat('Z', 'X' if abs(vec.x) > 0.5 else 'Y').inverted() class thickface(object): @@ -1070,7 +1064,7 @@ def main(context, f_uv = f.uv for j, v in enumerate(f.v): # XXX - note, between mathutils in 2.4 and 2.5 the order changed. - f_uv[j][:] = (v.co * MatQuat).xy + f_uv[j][:] = (MatQuat * v.co).xy if USER_SHARE_SPACE: diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 00a2f546382..ae44860c3dd 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -773,7 +773,7 @@ class WM_OT_doc_edit(bpy.types.Operator): def draw(self, context): layout = self.layout - layout.label(text=_("Descriptor ID: '%s'") % self.doc_id) + layout.label(text=_("Descriptor ID")+": '%s'" % self.doc_id) layout.prop(self, "doc_new", text="") def invoke(self, context, event): diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index ce6d0990f05..0a4d0b60514 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -394,6 +394,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel): col.operator("object.multires_higher_levels_delete", text="Delete Higher") col.operator("object.multires_reshape", text="Reshape") col.operator("object.multires_base_apply", text="Apply Base") + col.prop(md, "use_subsurf_uv") col.prop(md, "show_only_control_edges") layout.separator() diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 45c15bd1ce6..2a52ae23782 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -174,6 +174,7 @@ class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): row.prop(mat, "use_transparency") sub = row.column() sub.prop(mat, "offset_z") + sub.active = mat_type and mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY' row = layout.row() @@ -199,6 +200,7 @@ class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "shadow_cast_alpha", text="Casting Alpha") col.prop(mat, "use_cast_buffer_shadows") col.prop(mat, "use_cast_approximate") + col.prop(mat, "pass_index") class MATERIAL_PT_diffuse(MaterialButtonsPanel, bpy.types.Panel): @@ -729,7 +731,8 @@ class MATERIAL_PT_options(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "use_vertex_color_paint") col.prop(mat, "use_vertex_color_light") col.prop(mat, "use_object_color") - col.prop(mat, "pass_index") + if simple_material(base_mat): + col.prop(mat, "pass_index") class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel): diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index 4f398c9fbd9..63f8e88147b 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -19,8 +19,7 @@ # <pep8 compliant> import bpy from rna_prop_ui import PropertyPanel - -# TODO, "color_range" not in the UI +from blf import gettext as _ class WorldButtonsPanel(): @@ -64,7 +63,7 @@ class WORLD_PT_context_world(WorldButtonsPanel, bpy.types.Panel): class WORLD_PT_preview(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Preview" + bl_label = _("Preview") COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod @@ -77,7 +76,7 @@ class WORLD_PT_preview(WorldButtonsPanel, bpy.types.Panel): class WORLD_PT_world(WorldButtonsPanel, bpy.types.Panel): - bl_label = "World" + bl_label = _("World") COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): @@ -95,10 +94,14 @@ class WORLD_PT_world(WorldButtonsPanel, bpy.types.Panel): col.prop(world, "zenith_color") col.active = world.use_sky_blend row.column().prop(world, "ambient_color") + + row = layout.row() + row.prop(world, "exposure") + row.prop(world, "color_range") class WORLD_PT_ambient_occlusion(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Ambient Occlusion" + bl_label = _("Ambient Occlusion") COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): @@ -112,12 +115,12 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel, bpy.types.Panel): layout.active = light.use_ambient_occlusion split = layout.split() - split.prop(light, "ao_factor", text="Factor") + split.prop(light, "ao_factor", text=_("Factor")) split.prop(light, "ao_blend_type", text="") class WORLD_PT_environment_lighting(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Environment Lighting" + bl_label = _("Environment Lighting") COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): @@ -131,12 +134,12 @@ class WORLD_PT_environment_lighting(WorldButtonsPanel, bpy.types.Panel): layout.active = light.use_environment_light split = layout.split() - split.prop(light, "environment_energy", text="Energy") + split.prop(light, "environment_energy", text=_("Energy")) split.prop(light, "environment_color", text="") class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Indirect Lighting" + bl_label = _("Indirect Lighting") COMPAT_ENGINES = {'BLENDER_RENDER'} def draw_header(self, context): @@ -150,15 +153,15 @@ class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel): layout.active = light.use_indirect_light and light.gather_method == 'APPROXIMATE' split = layout.split() - split.prop(light, "indirect_factor", text="Factor") - split.prop(light, "indirect_bounces", text="Bounces") + split.prop(light, "indirect_factor", text=_("Factor")) + split.prop(light, "indirect_bounces", text=_("Bounces")) if light.gather_method == 'RAYTRACE': - layout.label(text="Only works with Approximate gather method") + layout.label(text=_("Only works with Approximate gather method")) class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Gather" + bl_label = _("Gather") COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): @@ -172,18 +175,18 @@ class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel): split = layout.split() col = split.column() - col.label(text="Attenuation:") + col.label(text=_("Attenuation:")) if light.gather_method == 'RAYTRACE': col.prop(light, "distance") col.prop(light, "use_falloff") sub = col.row() sub.active = light.use_falloff - sub.prop(light, "falloff_strength", text="Strength") + sub.prop(light, "falloff_strength", text=_("Strength")) if light.gather_method == 'RAYTRACE': col = split.column() - col.label(text="Sampling:") + col.label(text=_("Sampling:")) col.prop(light, "sample_method", text="") sub = col.column() @@ -198,15 +201,15 @@ class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel): if light.gather_method == 'APPROXIMATE': col = split.column() - col.label(text="Sampling:") + col.label(text=_("Sampling:")) col.prop(light, "passes") - col.prop(light, "error_threshold", text="Error") + col.prop(light, "error_threshold", text=_("Error")) col.prop(light, "use_cache") col.prop(light, "correction") class WORLD_PT_mist(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Mist" + bl_label = _("Mist") bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -235,7 +238,7 @@ class WORLD_PT_mist(WorldButtonsPanel, bpy.types.Panel): class WORLD_PT_stars(WorldButtonsPanel, bpy.types.Panel): - bl_label = "Stars" + bl_label = _("Stars") bl_options = {'DEFAULT_CLOSED'} COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -254,11 +257,11 @@ class WORLD_PT_stars(WorldButtonsPanel, bpy.types.Panel): col = split.column() col.prop(world.star_settings, "size") - col.prop(world.star_settings, "color_random", text="Colors") + col.prop(world.star_settings, "color_random", text=_("Colors")) col = split.column() - col.prop(world.star_settings, "distance_min", text="Min. Dist") - col.prop(world.star_settings, "average_separation", text="Separation") + col.prop(world.star_settings, "distance_min", text=_("Min. Dist")) + col.prop(world.star_settings, "average_separation", text=_("Separation")) class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, bpy.types.Panel): diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 6e0eded1d4c..15ba638dffb 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -64,7 +64,7 @@ class IMAGE_MT_view(bpy.types.Menu): ratios = [[1, 8], [1, 4], [1, 2], [1, 1], [2, 1], [4, 1], [8, 1]] for a, b in ratios: - text = _("Zoom %d:%d") % (a, b) + text = _("Zoom") + " %d:%d" % (a, b) layout.operator("image.view_zoom_ratio", text=text).ratio = a / b layout.separator() @@ -199,6 +199,10 @@ class IMAGE_MT_uvs_transform(bpy.types.Menu): layout.operator("transform.rotate") layout.operator("transform.resize") + layout.separator() + + layout.operator("transform.shear") + class IMAGE_MT_uvs_snap(bpy.types.Menu): bl_label = _("Snap") diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 4254ec3c9ab..fadd3ec73be 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -61,8 +61,10 @@ class INFO_HT_header(bpy.types.Header): layout.template_running_jobs() layout.template_reports_banner() - - layout.label(text=scene.statistics()) + + row = layout.row(align=True) + row.operator("wm.splash", text="", icon='BLENDER', emboss=False) + row.label(text=scene.statistics()) # XXX: this should be right-aligned to the RHS of the region layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index e7276b82aba..1f9d45e9bc4 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -358,13 +358,13 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, bpy.types.Panel): col = layout.column(align=True) row = col.row() - row.label(text=_("Final Length: %s") % bpy.utils.smpte_from_frame(strip.frame_final_duration)) + row.label(text=_("Final Length")+": %s" % bpy.utils.smpte_from_frame(strip.frame_final_duration)) row = col.row() row.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_duration) - row.label(text=_("Playhead: %d") % (frame_current - strip.frame_start)) + row.label(text=_("Playhead")+": %d" % (frame_current - strip.frame_start)) - col.label(text=_("Frame Offset %d:%d") % (strip.frame_offset_start, strip.frame_offset_end)) - col.label(text=_("Frame Still %d:%d") % (strip.frame_still_start, strip.frame_still_end)) + col.label(text=_("Frame Offset")+" %d:%d" % (strip.frame_offset_start, strip.frame_offset_end)) + col.label(text=_("Frame Still")+" %d:%d" % (strip.frame_still_start, strip.frame_still_end)) elem = False @@ -374,7 +374,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, bpy.types.Panel): elem = strip.elements[0] if elem and elem.orig_width > 0 and elem.orig_height > 0: - col.label(text=_("Orig Dim: %dx%d") % (elem.orig_width, elem.orig_height)) + col.label(text=_("Orig Dim")+": %dx%d" % (elem.orig_width, elem.orig_height)) class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel): @@ -668,7 +668,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, bpy.types.Panel): if scene: sta = scene.frame_start end = scene.frame_end - layout.label(text=_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1)) + layout.label(text=_("Original frame range")+": %d-%d (%d)" % (sta, end, end - sta + 1)) class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel): diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 0c3da2f5e1b..93e513acf0a 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# <pep8 compliant> +# <pep8-80 compliant> import bpy from blf import gettext as _ @@ -34,19 +34,21 @@ class TEXT_HT_header(bpy.types.Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("TEXT_MT_view") - sub.menu("TEXT_MT_text") + row.menu("TEXT_MT_view") + row.menu("TEXT_MT_text") + if text: - sub.menu("TEXT_MT_edit") - sub.menu("TEXT_MT_format") + row.menu("TEXT_MT_edit") + row.menu("TEXT_MT_format") + + row.menu("TEXT_MT_templates") if text and text.is_modified: - row = layout.row() - row.alert = True - row.operator("text.resolve_conflict", text="", icon='HELP') + sub = row.row() + sub.alert = True + sub.operator("text.resolve_conflict", text="", icon='HELP') - layout.template_ID(st, "text", new="text.new", unlink="text.unlink") + row.template_ID(st, "text", new="text.new", unlink="text.unlink") row = layout.row(align=True) row.prop(st, "show_line_numbers", text="") @@ -64,11 +66,13 @@ class TEXT_HT_header(bpy.types.Header): row = layout.row() if text.filepath: if text.is_dirty: - row.label(text="File: *%s (unsaved)" % text.filepath) + row.label(text=_("File")+": *%r " % text.filepath+_("(unsaved)")) else: - row.label(text="File: %s" % text.filepath) + row.label(text=_("File")+": %r" % text.filepath) else: - row.label(text="Text: External" if text.library else "Text: Internal") + row.label(text=_("Text: External") + if text.library + else _("Text: Internal")) class TEXT_PT_properties(bpy.types.Panel): @@ -151,8 +155,12 @@ class TEXT_MT_view(bpy.types.Menu): layout.separator() - layout.operator("text.move", text=_("Top of File")).type = 'FILE_TOP' - layout.operator("text.move", text=_("Bottom of File")).type = 'FILE_BOTTOM' + layout.operator("text.move", + text=_("Top of File"), + ).type = 'FILE_TOP' + layout.operator("text.move", + text=_("Bottom of File"), + ).type = 'FILE_BOTTOM' class TEXT_MT_text(bpy.types.Menu): @@ -186,19 +194,15 @@ class TEXT_MT_text(bpy.types.Menu): # XXX uiMenuItemO(head, 0, "text.refresh_pyconstraints"); #endif - layout.separator() - - layout.menu("TEXT_MT_templates") - class TEXT_MT_templates(bpy.types.Menu): - ''' - Creates the menu items by scanning scripts/templates - ''' - bl_label = _("Script Templates") + bl_label = _("Templates") def draw(self, context): - self.path_menu(bpy.utils.script_paths("templates"), "text.open", {"internal": True}) + self.path_menu(bpy.utils.script_paths("templates"), + "text.open", + {"internal": True}, + ) class TEXT_MT_edit_select(bpy.types.Menu): @@ -247,8 +251,12 @@ class TEXT_MT_edit_to3d(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.operator("text.to_3d_object", text=_("One Object")).split_lines = False - layout.operator("text.to_3d_object", text=_("One Object Per Line")).split_lines = True + layout.operator("text.to_3d_object", + text=_("One Object"), + ).split_lines = False + layout.operator("text.to_3d_object", + text=_("One Object Per Line"), + ).split_lines = True class TEXT_MT_edit(bpy.types.Menu): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 900d38d1693..fb5f2de7115 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -355,7 +355,7 @@ class USERPREF_PT_edit(bpy.types.Panel): col.prop(edit, "use_duplicate_lamp", text=_("Lamp")) col.prop(edit, "use_duplicate_material", text=_("Material")) col.prop(edit, "use_duplicate_texture", text=_("Texture")) - #col.prop(edit, "use_duplicate_fcurve", text="F-Curve") + #col.prop(edit, "use_duplicate_fcurve", text=_("F-Curve")) col.prop(edit, "use_duplicate_action", text=_("Action")) col.prop(edit, "use_duplicate_particle", text=_("Particle")) @@ -656,7 +656,7 @@ class USERPREF_PT_theme(bpy.types.Panel): col = split.column() for i, ui in enumerate(theme.bone_color_sets): - col.label(text=_("Color Set %d:") % (i + 1)) # i starts from 0 + col.label(text=_("Color Set")+" %d:" % (i + 1)) # i starts from 0 row = col.row() @@ -889,6 +889,16 @@ class USERPREF_PT_addons(bpy.types.Panel): return True return False + @staticmethod + def draw_error(layout, message): + lines = message.split("\n") + box = layout.box() + rowsub = box.row() + rowsub.label(lines[0]) + rowsub.label(icon='ERROR') + for l in lines[1:]: + box.label(l) + def draw(self, context): layout = self.layout @@ -909,6 +919,14 @@ class USERPREF_PT_addons(bpy.types.Panel): col = split.column() + # set in addon_utils.modules(...) + if addon_utils.error_duplicates: + self.draw_error(col, + "Multiple addons using the same name found!\n" + "likely a problem with the script search path.\n" + "(see console for details)", + ) + filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index feb90cadd68..fde11a0ac29 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -202,7 +202,7 @@ class InputKeyMapPanel: subcol = self.indented_layout(col, level + 1) subrow = subcol.row() subrow.prop(km, "show_expanded_items", text="", emboss=False) - subrow.label(text=_("%s (Global)") % _(km.name) ) + subrow.label(text="%s " % _(km.name) + _("(Global)") ) else: km.show_expanded_items = True diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 9ead8bb98df..b4adc3bf028 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -55,21 +55,13 @@ class VIEW3D_HT_header(bpy.types.Header): sub.menu("VIEW3D_MT_object") row = layout.row() - row.template_header_3D() - - # do in C for now since these buttons cant be both toggle AND exclusive. - ''' - if obj and obj.mode == 'EDIT' and obj.type == 'MESH': - row_sub = row.row(align=True) - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=0, icon='VERTEXSEL') - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=1, icon='EDGESEL') - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=2, icon='FACESEL') - ''' + # Contains buttons like Mode, Pivot, Manipulator, Layer, Mesh Select Mode... + row.template_header_3D() if obj: # Particle edit if obj.mode == 'PARTICLE_EDIT': - row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True, toggle=True) + row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True) # Occlude geometry if view.viewport_shade in {'SOLID', 'SHADED', 'TEXTURED'} and (obj.mode == 'PARTICLE_EDIT' or (obj.mode == 'EDIT' and obj.type == 'MESH')): @@ -88,19 +80,22 @@ class VIEW3D_HT_header(bpy.types.Header): row.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) # Snap + snap_element = toolsettings.snap_element row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") row.prop(toolsettings, "snap_element", text="", icon_only=True) - if toolsettings.snap_element != 'INCREMENT': + if snap_element != 'INCREMENT': row.prop(toolsettings, "snap_target", text="") - if obj and obj.mode == 'OBJECT': - row.prop(toolsettings, "use_snap_align_rotation", text="") - if toolsettings.snap_element == 'VOLUME': + if obj: + if obj.mode == 'OBJECT': + row.prop(toolsettings, "use_snap_align_rotation", text="") + elif obj.mode == 'EDIT': + row.prop(toolsettings, "use_snap_self", text="") + + if snap_element == 'VOLUME': row.prop(toolsettings, "use_snap_peel_object", text="") - elif toolsettings.snap_element == 'FACE': + elif snap_element == 'FACE': row.prop(toolsettings, "use_snap_project", text="") - if toolsettings.use_snap_project and obj.mode == 'EDIT': - row.prop(toolsettings, "use_snap_project_self", text="") # OpenGL render row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index f2370ec39ac..d029de3786c 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -117,7 +117,8 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel): col.operator("transform.translate") col.operator("transform.rotate") col.operator("transform.resize", text="Scale") - col.operator("transform.shrink_fatten", text="Along Normal") + col.operator("transform.shrink_fatten", text=_("Shrink/Fatten")) + col.operator("transform.push_pull", text=_("Push/Pull")) col = layout.column(align=True) col.label(text="Deform:") diff --git a/release/scripts/templates/batch_export.py b/release/scripts/templates/batch_export.py new file mode 100755 index 00000000000..aa0e601725b --- /dev/null +++ b/release/scripts/templates/batch_export.py @@ -0,0 +1,33 @@ +# exports each selected object into its own file + +import bpy +import os + +# export to blend file location +basedir = os.path.dirname(bpy.data.filepath) + +if not basedir: + raise Exception("Blend file is not saved") + +selection = bpy.context.selected_objects + +bpy.ops.object.select_all(action='DESELECT') + +for obj in selection: + + obj.select = True + + name = bpy.path.clean_name(obj.name) + fn = os.path.join(basedir, name) + + bpy.ops.export_scene.fbx(filepath=fn + ".fbx", use_selection=True) + + ## Can be used for multiple formats + # bpy.ops.export_scene.x3d(filepath=fn + ".x3d", use_selection=True) + + obj.select = False + + print("written:", fn) + +for obj in selection: + obj.select = True diff --git a/release/scripts/templates/ui_menu.py b/release/scripts/templates/ui_menu.py new file mode 100755 index 00000000000..d3923b5b083 --- /dev/null +++ b/release/scripts/templates/ui_menu.py @@ -0,0 +1,49 @@ +import bpy + + +class CustomMenu(bpy.types.Menu): + bl_label = "Custom Menu" + bl_idname = "OBJECT_MT_custom_menu" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.open_mainfile") + layout.operator("wm.save_as_mainfile").copy = True + + layout.operator("object.shade_smooth") + + layout.label(text="Hello world!", icon='WORLD_DATA') + + # use an operator enum property to populate a submenu + layout.operator_menu_enum("object.select_by_type", + property="type", + text="Select All by Type...", + ) + + # call another menu + layout.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map" + + +def draw_item(self, context): + layout = self.layout + layout.menu(CustomMenu.bl_idname) + + +def register(): + bpy.utils.register_class(CustomMenu) + + # lets add ourselves to the main header + bpy.types.INFO_HT_header.append(draw_item) + + +def unregister(): + bpy.utils.unregister_class(CustomMenu) + + bpy.types.INFO_HT_header.remove(draw_item) + +if __name__ == "__main__": + register() + + # The menu can also be called from scripts + bpy.ops.wm.call_menu(name=CustomMenu.bl_idname) diff --git a/release/scripts/templates/ui_menu_simple.py b/release/scripts/templates/ui_menu_simple.py new file mode 100755 index 00000000000..2129dfd81a4 --- /dev/null +++ b/release/scripts/templates/ui_menu_simple.py @@ -0,0 +1,26 @@ +import bpy + + +class SimpleCustomMenu(bpy.types.Menu): + bl_label = "Simple Custom Menu" + bl_idname = "OBJECT_MT_simple_custom_menu" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.open_mainfile") + layout.operator("wm.save_as_mainfile") + + +def register(): + bpy.utils.register_class(SimpleCustomMenu) + + +def unregister(): + bpy.utils.unregister_class(SimpleCustomMenu) + +if __name__ == "__main__": + register() + + # The menu can also be called from scripts + bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname) diff --git a/release/scripts/templates/panel_simple.py b/release/scripts/templates/ui_panel_simple.py index e5bf70cb654..cde6126b626 100644..100755 --- a/release/scripts/templates/panel_simple.py +++ b/release/scripts/templates/ui_panel_simple.py @@ -1,8 +1,9 @@ import bpy -class OBJECT_PT_hello(bpy.types.Panel): +class HelloWorldPanel(bpy.types.Panel): bl_label = "Hello World Panel" + bl_idname = "OBJECT_PT_hello" bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "object" @@ -22,11 +23,11 @@ class OBJECT_PT_hello(bpy.types.Panel): def register(): - bpy.utils.register_class(OBJECT_PT_hello) + bpy.utils.register_class(HelloWorldPanel) def unregister(): - bpy.utils.unregister_class(OBJECT_PT_hello) + bpy.utils.unregister_class(HelloWorldPanel) if __name__ == "__main__": |