diff options
Diffstat (limited to 'release/scripts/modules/bpy_extras')
-rw-r--r-- | release/scripts/modules/bpy_extras/anim_utils.py | 56 | ||||
-rw-r--r-- | release/scripts/modules/bpy_extras/io_utils.py | 65 | ||||
-rw-r--r-- | release/scripts/modules/bpy_extras/keyconfig_utils.py | 8 | ||||
-rw-r--r-- | release/scripts/modules/bpy_extras/object_utils.py | 58 | ||||
-rw-r--r-- | release/scripts/modules/bpy_extras/view3d_utils.py | 37 |
5 files changed, 185 insertions, 39 deletions
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index d87c207e2d0..021a8bbb530 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -25,6 +25,7 @@ __all__ = ( import bpy +# XXX visual keying is actually always considered as True in this code... def bake_action(frame_start, frame_end, frame_step=1, @@ -73,7 +74,7 @@ def bake_action(frame_start, # ------------------------------------------------------------------------- # Helper Functions and vars - def pose_frame_info(obj, do_visual_keying): + def pose_frame_info(obj): matrix = {} for name, pbone in obj.pose.bones.items(): if do_visual_keying: @@ -84,16 +85,29 @@ def bake_action(frame_start, return matrix if do_parents_clear: - def obj_frame_info(obj, do_visual_keying): - parent = obj.parent - matrix = obj.matrix_local if do_visual_keying else obj.matrix_local - if parent: - return parent.matrix_world * matrix - else: - return matrix.copy() + if do_visual_keying: + def obj_frame_info(obj): + return obj.matrix_world.copy() + else: + def obj_frame_info(obj): + parent = obj.parent + matrix = obj.matrix_basis + if parent: + return parent.matrix_world * matrix + else: + return matrix.copy() else: - def obj_frame_info(obj, do_visual_keying): - return obj.matrix_local.copy() if do_visual_keying else obj.matrix_local.copy() + if do_visual_keying: + def obj_frame_info(obj): + parent = obj.parent + matrix = obj.matrix_world + if parent: + return parent.matrix_world.inverted_safe() * matrix + else: + return matrix.copy() + else: + def obj_frame_info(obj): + return obj.matrix_basis.copy() # ------------------------------------------------------------------------- # Setup the Context @@ -123,9 +137,16 @@ def bake_action(frame_start, scene.frame_set(f) scene.update() if do_pose: - pose_info.append(pose_frame_info(obj, do_visual_keying)) + pose_info.append(pose_frame_info(obj)) if do_object: - obj_info.append(obj_frame_info(obj, do_visual_keying)) + obj_info.append(obj_frame_info(obj)) + + # ------------------------------------------------------------------------- + # Clean (store initial data) + if do_clean and action is not None: + clean_orig_data = {fcu: {p.co[1] for p in fcu.keyframe_points} for fcu in action.fcurves} + else: + clean_orig_data = {} # ------------------------------------------------------------------------- # Create action @@ -216,12 +237,19 @@ def bake_action(frame_start, if do_clean: for fcu in action.fcurves: + fcu_orig_data = clean_orig_data.get(fcu, set()) + keyframe_points = fcu.keyframe_points i = 1 - while i < len(fcu.keyframe_points) - 1: + while i < len(keyframe_points) - 1: + val = keyframe_points[i].co[1] + + if val in fcu_orig_data: + i += 1 + continue + val_prev = keyframe_points[i - 1].co[1] val_next = keyframe_points[i + 1].co[1] - val = keyframe_points[i].co[1] if abs(val - val_prev) + abs(val - val_next) < 0.0001: keyframe_points.remove(keyframe_points[i]) diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index b1877a9d439..65ccc3f8dc3 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -21,6 +21,7 @@ __all__ = ( "ExportHelper", "ImportHelper", + "orientation_helper_factory", "axis_conversion", "axis_conversion_ensure", "create_derived_objects", @@ -34,7 +35,11 @@ __all__ = ( ) import bpy -from bpy.props import StringProperty, BoolProperty, EnumProperty +from bpy.props import ( + StringProperty, + BoolProperty, + EnumProperty, + ) def _check_axis_conversion(op): @@ -60,6 +65,12 @@ class ExportHelper: options={'HIDDEN'}, ) + # needed for mix-ins + order = [ + "filepath", + "check_existing", + ] + # subclasses can override with decorator # True == use ext, False == no ext, None == do nothing. check_extension = True @@ -108,6 +119,11 @@ class ImportHelper: subtype='FILE_PATH', ) + # needed for mix-ins + order = [ + "filepath", + ] + def invoke(self, context, event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} @@ -116,6 +132,51 @@ class ImportHelper: return _check_axis_conversion(self) +def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'): + members = {} + + def _update_axis_forward(self, context): + if self.axis_forward[-1] == self.axis_up[-1]: + self.axis_up = self.axis_up[0:-1] + 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3] + + members['axis_forward'] = EnumProperty( + name="Forward", + items=(('X', "X Forward", ""), + ('Y', "Y Forward", ""), + ('Z', "Z Forward", ""), + ('-X', "-X Forward", ""), + ('-Y', "-Y Forward", ""), + ('-Z', "-Z Forward", ""), + ), + default=axis_forward, + update=_update_axis_forward, + ) + + def _update_axis_up(self, context): + if self.axis_up[-1] == self.axis_forward[-1]: + self.axis_forward = self.axis_forward[0:-1] + 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3] + + members['axis_up'] = EnumProperty( + name="Up", + items=(('X', "X Up", ""), + ('Y', "Y Up", ""), + ('Z', "Z Up", ""), + ('-X', "-X Up", ""), + ('-Y', "-Y Up", ""), + ('-Z', "-Z Up", ""), + ), + default=axis_up, + update=_update_axis_up, + ) + + members["order"] = [ + "axis_forward", + "axis_up", + ] + + return type(name, (object,), members) + + # Axis conversion function, not pretty LUT # use lookup table to convert between any axis _axis_convert_matrix = ( @@ -311,7 +372,7 @@ def unpack_list(list_of_tuples): # same as above except that it adds 0 for triangle faces def unpack_face_list(list_of_tuples): - #allocate the entire list + # allocate the entire list flat_ls = [0] * (len(list_of_tuples) * 4) i = 0 diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index c50b320dceb..7e4c9e885e7 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -32,7 +32,10 @@ KM_HIERARCHY = [ ('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region) ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region) - ('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region) + + ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region) + ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []), + ]), ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform) ('Object Mode', 'EMPTY', 'WINDOW', []), @@ -56,6 +59,7 @@ KM_HIERARCHY = [ ('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []), ('Paint Stroke Modal', 'EMPTY', 'WINDOW', []), + ('Paint Curve', 'EMPTY', 'WINDOW', []), ('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change @@ -241,7 +245,7 @@ def keyconfig_export(wm, kc, filepath): # the default blender keyconfig, recreating the current setup from a fresh blender # without needing to export keymaps which haven't been edited. - class FakeKeyConfig(): + class FakeKeyConfig: keymaps = [] edited_kc = FakeKeyConfig() for km in wm.keyconfigs.user.keymaps: diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 01390760c76..c2c306e5145 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -31,7 +31,11 @@ __all__ = ( import bpy -from bpy.props import BoolProperty, FloatVectorProperty +from bpy.props import ( + BoolProperty, + BoolVectorProperty, + FloatVectorProperty, + ) def add_object_align_init(context, operator): @@ -99,7 +103,7 @@ def add_object_align_init(context, operator): return location * rotation -def object_data_add(context, obdata, operator=None, use_active_layer=True): +def object_data_add(context, obdata, operator=None, use_active_layer=True, name=None): """ Add an object using the view context and preference to to initialize the location, rotation and layer. @@ -110,6 +114,8 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True): :type obdata: valid object data type or None. :arg operator: The operator, checked for location and rotation properties. :type operator: :class:`bpy.types.Operator` + :arg name: Optional name + :type name: string :return: the newly created object in the scene. :rtype: :class:`bpy.types.ObjectBase` """ @@ -119,7 +125,10 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True): for ob in scene.objects: ob.select = False - obj_new = bpy.data.objects.new(obdata.name, obdata) + if name is None: + name = "Object" if obdata is None else obdata.name + + obj_new = bpy.data.objects.new(name, obdata) base = scene.objects.link(obj_new) base.select = True @@ -128,16 +137,22 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True): if context.space_data and context.space_data.type == 'VIEW_3D': v3d = context.space_data - if use_active_layer: - if v3d and v3d.local_view: - base.layers_from_view(context.space_data) - base.layers[scene.active_layer] = True - else: - base.layers = [True if i == scene.active_layer - else False for i in range(len(scene.layers))] + if operator is not None and any(operator.layers): + base.layers = operator.layers else: - if v3d: - base.layers_from_view(context.space_data) + if use_active_layer: + if v3d and v3d.local_view: + base.layers_from_view(context.space_data) + base.layers[scene.active_layer] = True + else: + base.layers = [True if i == scene.active_layer + else False for i in range(len(scene.layers))] + else: + if v3d: + base.layers_from_view(context.space_data) + + if operator is not None: + operator.layers = base.layers obj_new.matrix_world = add_object_align_init(context, operator) @@ -150,7 +165,7 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True): obj_act.mode == 'EDIT' and obj_act.type == obj_new.type): - _obdata = bpy.data.meshes.new(obdata.name) + _obdata = bpy.data.meshes.new(name) obj_act = bpy.data.objects.new(_obdata.name, _obdata) obj_act.matrix_world = obj_new.matrix_world scene.objects.link(obj_act) @@ -166,10 +181,11 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True): obj_act.select = True scene.update() # apply location - #scene.objects.active = obj_new + # scene.objects.active = obj_new bpy.ops.object.join() # join into the active. - bpy.data.meshes.remove(obdata) + if obdata: + bpy.data.meshes.remove(obdata) # base is freed, set to active object base = scene.object_bases.active @@ -200,6 +216,12 @@ class AddObjectHelper: name="Rotation", subtype='EULER', ) + layers = BoolVectorProperty( + name="Layers", + size=20, + subtype='LAYER', + options={'HIDDEN', 'SKIP_SAVE'}, + ) @classmethod def poll(self, context): @@ -281,7 +303,8 @@ def world_to_camera_view(scene, obj, coord): Returns the camera space coords for a 3d point. (also known as: normalized device coordinates - NDC). - Where (0, 0) is the bottom left and (1, 1) is the top right of the camera frame. + Where (0, 0) is the bottom left and (1, 1) + is the top right of the camera frame. values outside 0-1 are also supported. A negative 'z' value means the point is behind the camera. @@ -294,7 +317,8 @@ def world_to_camera_view(scene, obj, coord): :type obj: :class:`bpy.types.Object` :arg coord: World space location. :type coord: :class:`mathutils.Vector` - :return: a vector where X and Y map to the view plane and Z is the depth on the view axis. + :return: a vector where X and Y map to the view plane and + Z is the depth on the view axis. :rtype: :class:`mathutils.Vector` """ from mathutils import Vector diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index b25024fca9b..4aa06262970 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -63,10 +63,20 @@ def region_2d_to_vector_3d(region, rv3d, coord): return view_vector -def region_2d_to_origin_3d(region, rv3d, coord): +def region_2d_to_origin_3d(region, rv3d, coord, clamp=None): """ Return the 3d view origin from the region relative 2d coords. + .. note:: + + Orthographic views have a less obvious origin, + the far clip is used to define the viewport near/far extents. + Since far clip can be a very large value, + the result may give with numeric precision issues. + + To avoid this problem, you can optionally clamp the far clip to a + smaller value based on the data you're operating on. + :arg region: region of the 3D viewport, typically bpy.context.region. :type region: :class:`bpy.types.Region` :arg rv3d: 3D region data, typically bpy.context.space_data.region_3d. @@ -74,6 +84,9 @@ def region_2d_to_origin_3d(region, rv3d, coord): :arg coord: 2d coordinates relative to the region; (event.mouse_region_x, event.mouse_region_y) for example. :type coord: 2d vector + :arg clamp: Clamp the maximum far-clip value used. + (negative value will move the offset away from the view_location) + :type clamp: float or None :return: The origin of the viewpoint in 3d space. :rtype: :class:`mathutils.Vector` """ @@ -89,6 +102,20 @@ def region_2d_to_origin_3d(region, rv3d, coord): origin_start = ((persinv.col[0].xyz * dx) + (persinv.col[1].xyz * dy) + viewinv.translation) + + if clamp != 0.0: + if rv3d.view_perspective != 'CAMERA': + # this value is scaled to the far clip already + origin_offset = persinv.col[2].xyz + if clamp is not None: + if clamp < 0.0: + origin_offset.negate() + clamp = -clamp + if origin_offset.length > clamp: + origin_offset.length = clamp + + origin_start -= origin_offset + return origin_start @@ -135,7 +162,7 @@ def region_2d_to_location_3d(region, rv3d, coord, depth_location): )[0] -def location_3d_to_region_2d(region, rv3d, coord): +def location_3d_to_region_2d(region, rv3d, coord, default=None): """ Return the *region* relative 2d location of a 3d position. @@ -145,8 +172,10 @@ def location_3d_to_region_2d(region, rv3d, coord): :type rv3d: :class:`bpy.types.RegionView3D` :arg coord: 3d worldspace location. :type coord: 3d vector + :arg default: Return this value if ``coord`` + is behind the origin of a perspective view. :return: 2d location - :rtype: :class:`mathutils.Vector` + :rtype: :class:`mathutils.Vector` or ``default`` argument. """ from mathutils import Vector @@ -159,4 +188,4 @@ def location_3d_to_region_2d(region, rv3d, coord): height_half + height_half * (prj.y / prj.w), )) else: - return None + return default |