diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index cc132a2c3b2..82029e3a7af 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -25,6 +25,10 @@ elseif(CMAKE_COMPILER_IS_GNUCC) set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2 -mfpmath=sse") set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CYCLES_SSE2_KERNEL_FLAGS "-ffast-math -msse -msse2") + set(CYCLES_SSE3_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") endif() # for OSL diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 4a72341cd8c..d1e3d64d572 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -304,7 +304,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P } if (b_dupli_ob) { - object->dupli_generated = get_float3(b_dupli_ob.orco()); + object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f); object->dupli_uv = get_float2(b_dupli_ob.uv()); } else { diff --git a/release/scripts/freestyle/style_modules/ChainingIterators.py b/release/scripts/freestyle/style_modules/ChainingIterators.py index 03ad837aa28..b908fad0b89 100644 --- a/release/scripts/freestyle/style_modules/ChainingIterators.py +++ b/release/scripts/freestyle/style_modules/ChainingIterators.py @@ -24,6 +24,8 @@ from freestyle import AdjacencyIterator, ChainingIterator, ExternalContourUP1D, Nature, TVertex from freestyle import ContextFunctions as CF +import bpy + ## the natural chaining iterator ## It follows the edges of same nature following the topology of ## objects with preseance on silhouettes, then borders, @@ -212,7 +214,7 @@ class pySketchyChainSilhouetteIterator(ChainingIterator): visitNext = 1 break if visitNext != 0: - break + break count = count+1 winner = ve it.increment() @@ -238,14 +240,22 @@ class pySketchyChainingIterator(ChainingIterator): self._timeStamp = CF.get_time_stamp()+self._nRounds def traverse(self, iter): winner = None + found = False it = AdjacencyIterator(iter) while not it.is_end: ve = it.object if ve.id == self.current_edge.id: + found = True it.increment() continue winner = ve it.increment() + if not found: + # This is a fatal error condition: self.current_edge must be found + # among the edges seen by the AdjacencyIterator [bug #35695]. + if bpy.app.debug_freestyle: + print('pySketchyChainingIterator: current edge not found') + return None if winner is None: winner = self.current_edge if winner.chaining_time_stamp == self._timeStamp: diff --git a/release/scripts/freestyle/style_modules/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py index 71cfdce43f0..5b773cd7a6d 100644 --- a/release/scripts/freestyle/style_modules/parameter_editor.py +++ b/release/scripts/freestyle/style_modules/parameter_editor.py @@ -32,7 +32,7 @@ from freestyle import BackboneStretcherShader, BezierCurveShader, BinaryPredicat FalseBP1D, FalseUP1D, GuidingLinesShader, Interface0DIterator, Nature, Noise, Normal2DF0D, Operators, \ PolygonalizationShader, QuantitativeInvisibilityF1D, QuantitativeInvisibilityUP1D, SamplingShader, \ SpatialNoiseShader, StrokeAttribute, StrokeShader, TipRemoverShader, TrueBP1D, TrueUP1D, UnaryPredicate0D, \ - UnaryPredicate1D, VertexOrientation2DF0D, WithinImageBoundaryUP1D + UnaryPredicate1D, VertexOrientation2DF0D, WithinImageBoundaryUP1D, ContextFunctions from Functions0D import CurveMaterialF0D from PredicatesU1D import pyNatureUP1D from logical_operators import AndUP1D, NotUP1D, OrUP1D @@ -1046,17 +1046,7 @@ def process(layer_name, lineset_name): selection_criteria.append(upred) # prepare selection criteria by image border if lineset.select_by_image_border: - fac = scene.render.resolution_percentage / 100.0 - w = scene.render.resolution_x * fac - h = scene.render.resolution_y * fac - if scene.render.use_border: - xmin = scene.render.border_min_x * w - xmax = scene.render.border_max_x * w - ymin = scene.render.border_min_y * h - ymax = scene.render.border_max_y * h - else: - xmin, xmax = 0.0, float(w) - ymin, ymax = 0.0, float(h) + xmin, ymin, xmax, ymax = ContextFunctions.get_border() upred = WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax) selection_criteria.append(upred) # select feature edges diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index c9ed91d3a83..d87c207e2d0 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -31,6 +31,7 @@ def bake_action(frame_start, only_selected=False, do_pose=True, do_object=True, + do_visual_keying=True, do_constraint_clear=False, do_parents_clear=False, do_clean=False, @@ -53,7 +54,9 @@ def bake_action(frame_start, :type do_pose: bool :arg do_object: Bake objects. :type do_object: bool - :arg do_constraint_clear: Remove constraints (and do 'visual keying'). + :arg do_visual_keying: Use the final transformations for baking ('visual keying') + :type do_visual_keying: bool + :arg do_constraint_clear: Remove constraints after baking. :type do_constraint_clear: bool :arg do_parents_clear: Unparent after baking objects. :type do_parents_clear: bool @@ -83,14 +86,14 @@ def bake_action(frame_start, 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_basis + matrix = obj.matrix_local if do_visual_keying else obj.matrix_local 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_basis.copy() + return obj.matrix_local.copy() if do_visual_keying else obj.matrix_local.copy() # ------------------------------------------------------------------------- # Setup the Context @@ -118,10 +121,11 @@ def bake_action(frame_start, for f in frame_range: scene.frame_set(f) + scene.update() if do_pose: - pose_info.append(pose_frame_info(obj, do_constraint_clear)) + pose_info.append(pose_frame_info(obj, do_visual_keying)) if do_object: - obj_info.append(obj_frame_info(obj, do_constraint_clear)) + obj_info.append(obj_frame_info(obj, do_visual_keying)) # ------------------------------------------------------------------------- # Create action diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index ed20cb22297..6193611504e 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -190,6 +190,11 @@ class BakeAction(Operator): description="Only key selected object/bones", default=True, ) + visual_keying = BoolProperty( + name="Visual Keying", + description="Keyframe from the final transformations (with constraints applied)", + default=False, + ) clear_constraints = BoolProperty( name="Clear Constraints", description="Remove all constraints from keyed object/bones, and do 'visual' keying", @@ -220,6 +225,7 @@ class BakeAction(Operator): only_selected=self.only_selected, do_pose='POSE' in self.bake_types, do_object='OBJECT' in self.bake_types, + do_visual_keying=self.visual_keying, do_constraint_clear=self.clear_constraints, do_parents_clear=self.clear_parents, do_clean=True, diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 3919ecdd72f..63d9aa31ddd 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -471,24 +471,6 @@ class WM_OT_context_cycle_array(Operator): return operator_path_undo_return(context, data_path) -class WM_MT_context_menu_enum(Menu): - bl_label = "" - data_path = "" # BAD DESIGN, set from operator below. - - def draw(self, context): - data_path = self.data_path - value = context_path_validate(context, data_path) - if value is Ellipsis: - return {'PASS_THROUGH'} - base_path, prop_string = data_path.rsplit(".", 1) - value_base = context_path_validate(context, base_path) - prop = value_base.bl_rna.properties[prop_string] - - layout = self.layout - layout.label(prop.name, icon=prop.icon) - layout.prop(value_base, prop_string, expand=True) - - class WM_OT_context_menu_enum(Operator): bl_idname = "wm.context_menu_enum" bl_label = "Context Enum Menu" @@ -497,8 +479,21 @@ class WM_OT_context_menu_enum(Operator): def execute(self, context): data_path = self.data_path - WM_MT_context_menu_enum.data_path = data_path - bpy.ops.wm.call_menu(name="WM_MT_context_menu_enum") + value = context_path_validate(context, data_path) + + if value is Ellipsis: + return {'PASS_THROUGH'} + + base_path, prop_string = data_path.rsplit(".", 1) + value_base = context_path_validate(context, base_path) + prop = value_base.bl_rna.properties[prop_string] + + def draw_cb(self, context): + layout = self.layout + layout.prop(value_base, prop_string, expand=True) + + context.window_manager.popup_menu(draw_func=draw_cb, title=prop.name, icon=prop.icon) + return {'PASS_THROUGH'} diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index 594f724c6e3..b9f2e8406c6 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -72,7 +72,6 @@ _modules = [ "space_sequencer", "space_text", "space_time", - "space_userpref_keymap", "space_userpref", "space_view3d", "space_view3d_toolbar", diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index b6ad14196cd..b5461c45433 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -33,7 +33,7 @@ class MESH_MT_vertex_group_specials(Menu): layout.operator("object.vertex_group_copy", icon='COPY_ID') layout.operator("object.vertex_group_copy_to_linked", icon='LINK_AREA') layout.operator("object.vertex_group_copy_to_selected", icon='LINK_AREA') - layout.operator("object.vertex_group_mirror", icon='ARROW_LEFTRIGHT') + layout.operator("object.vertex_group_mirror", icon='ARROW_LEFTRIGHT').use_topology = False layout.operator("object.vertex_group_mirror", text="Mirror Vertex Group (Topology)", icon='ARROW_LEFTRIGHT').use_topology = True layout.operator("object.vertex_group_remove_from", icon='X', text="Remove from All Groups").use_all_groups = True layout.operator("object.vertex_group_remove_from", icon='X', text="Clear Active Group").use_all_verts = True @@ -53,7 +53,7 @@ class MESH_MT_shape_key_specials(Menu): layout.operator("object.shape_key_transfer", icon='COPY_ID') # icon is not ideal layout.operator("object.join_shapes", icon='COPY_ID') # icon is not ideal - layout.operator("object.shape_key_mirror", icon='ARROW_LEFTRIGHT') + layout.operator("object.shape_key_mirror", icon='ARROW_LEFTRIGHT').use_topology = False layout.operator("object.shape_key_mirror", text="Mirror Shape Key (Topology)", icon='ARROW_LEFTRIGHT').use_topology = True layout.operator("object.shape_key_add", icon='ZOOMIN', text="New Shape From Mix").from_mix = True layout.operator("object.shape_key_remove", icon='X', text="Delete All Shapes").all = True diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 54387f10a8d..a5e4b6e10bf 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -917,9 +917,6 @@ class USERPREF_PT_file(Panel): col.prop(system, "author", text="") -from bl_ui.space_userpref_keymap import InputKeyMapPanel - - class USERPREF_MT_ndof_settings(Menu): # accessed from the window key-bindings in C (only) bl_label = "3D Mouse Settings" @@ -960,9 +957,25 @@ class USERPREF_MT_ndof_settings(Menu): layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM') -class USERPREF_PT_input(Panel, InputKeyMapPanel): +class USERPREF_MT_keyconfigs(Menu): + bl_label = "KeyPresets" + preset_subdir = "keyconfig" + preset_operator = "wm.keyconfig_activate" + + def draw(self, context): + props = self.layout.operator("wm.context_set_value", text="Blender (default)") + props.data_path = "window_manager.keyconfigs.active" + props.value = "context.window_manager.keyconfigs.default" + + # now draw the presets + Menu.draw_preset(self, context) + + +class USERPREF_PT_input(Panel): bl_space_type = 'USER_PREFERENCES' bl_label = "Input" + bl_region_type = 'WINDOW' + bl_options = {'HIDE_HEADER'} @classmethod def poll(cls, context): @@ -1039,6 +1052,8 @@ class USERPREF_PT_input(Panel, InputKeyMapPanel): row.separator() def draw(self, context): + from bl_ui.space_userpref_keymap import draw_keymaps + layout = self.layout #import time @@ -1055,7 +1070,7 @@ class USERPREF_PT_input(Panel, InputKeyMapPanel): self.draw_input_prefs(inputs, split) # Keymap Settings - self.draw_keymaps(context, split) + draw_keymaps(context, split) #print("runtime", time.time() - start) diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py index 8d6eb2c623d..727e9935bcc 100644 --- a/release/scripts/startup/bl_ui/space_userpref_keymap.py +++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py @@ -17,375 +17,368 @@ # ##### END GPL LICENSE BLOCK ##### # + +__all__ = ( + "draw_entry", + "draw_km", + "draw_kmi", + "draw_filtered", + "draw_hierarchy", + "draw_keymaps", + ) + + import bpy -from bpy.types import Menu from bpy.app.translations import pgettext_iface as iface_ from bpy.app.translations import contexts as i18n_contexts -class USERPREF_MT_keyconfigs(Menu): - bl_label = "KeyPresets" - preset_subdir = "keyconfig" - preset_operator = "wm.keyconfig_activate" +def _indented_layout(layout, level): + indentpx = 16 + if level == 0: + level = 0.0001 # Tweak so that a percentage of 0 won't split by half + indent = level * indentpx / bpy.context.region.width - def draw(self, context): - props = self.layout.operator("wm.context_set_value", text="Blender (default)") - props.data_path = "window_manager.keyconfigs.active" - props.value = "context.window_manager.keyconfigs.default" - - # now draw the presets - Menu.draw_preset(self, context) + split = layout.split(percentage=indent) + col = split.column() + col = split.column() + return col -class InputKeyMapPanel: - bl_space_type = 'USER_PREFERENCES' - bl_label = "Input" - bl_region_type = 'WINDOW' - bl_options = {'HIDE_HEADER'} +def draw_entry(display_keymaps, entry, col, level=0): + idname, spaceid, regionid, children = entry - def draw_entry(self, display_keymaps, entry, col, level=0): - idname, spaceid, regionid, children = entry + for km, kc in display_keymaps: + if km.name == idname and km.space_type == spaceid and km.region_type == regionid: + draw_km(display_keymaps, kc, km, children, col, level) - for km, kc in display_keymaps: - if km.name == idname and km.space_type == spaceid and km.region_type == regionid: - self.draw_km(display_keymaps, kc, km, children, col, level) - - ''' + ''' + km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid) + if not km: + kc = defkc km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid) - if not km: - kc = defkc - km = kc.keymaps.find(idname, space_type=spaceid, region_type=regionid) - if km: - self.draw_km(kc, km, children, col, level) - ''' + if km: + draw_km(kc, km, children, col, level) + ''' - def indented_layout(self, layout, level): - indentpx = 16 - if level == 0: - level = 0.0001 # Tweak so that a percentage of 0 won't split by half - indent = level * indentpx / bpy.context.region.width - split = layout.split(percentage=indent) - col = split.column() - col = split.column() - return col +def draw_km(display_keymaps, kc, km, children, layout, level): + km = km.active() - def draw_km(self, display_keymaps, kc, km, children, layout, level): - km = km.active() + layout.context_pointer_set("keymap", km) - layout.context_pointer_set("keymap", km) + col = _indented_layout(layout, level) - col = self.indented_layout(layout, level) + row = col.row() + row.prop(km, "show_expanded_children", text="", emboss=False) + row.label(text=km.name, text_ctxt=i18n_contexts.id_windowmanager) - row = col.row() - row.prop(km, "show_expanded_children", text="", emboss=False) - row.label(text=km.name, text_ctxt=i18n_contexts.id_windowmanager) + row.label() + row.label() - row.label() + if km.is_modal: + row.label(text="", icon='LINKED') + if km.is_user_modified: + row.operator("wm.keymap_restore", text="Restore") + else: row.label() - if km.is_modal: - row.label(text="", icon='LINKED') - if km.is_user_modified: - row.operator("wm.keymap_restore", text="Restore") + if km.show_expanded_children: + if children: + # Put the Parent key map's entries in a 'global' sub-category + # equal in hierarchy to the other children categories + subcol = _indented_layout(col, level + 1) + subrow = subcol.row() + subrow.prop(km, "show_expanded_items", text="", emboss=False) + subrow.label(text=iface_("%s (Global)") % km.name, translate=False) else: - row.label() + km.show_expanded_items = True - if km.show_expanded_children: - if children: - # Put the Parent key map's entries in a 'global' sub-category - # equal in hierarchy to the other children categories - subcol = self.indented_layout(col, level + 1) - subrow = subcol.row() - subrow.prop(km, "show_expanded_items", text="", emboss=False) - subrow.label(text=iface_("%s (Global)") % km.name, translate=False) - else: - km.show_expanded_items = True + # Key Map items + if km.show_expanded_items: + for kmi in km.keymap_items: + draw_kmi(display_keymaps, kc, km, kmi, col, level + 1) - # Key Map items - if km.show_expanded_items: - for kmi in km.keymap_items: - self.draw_kmi(display_keymaps, kc, km, kmi, col, level + 1) - - # "Add New" at end of keymap item list - col = self.indented_layout(col, level + 1) - subcol = col.split(percentage=0.2).column() - subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager, - icon='ZOOMIN') - - col.separator() - - # Child key maps - if children: - subcol = col.column() - row = subcol.row() - - for entry in children: - self.draw_entry(display_keymaps, entry, col, level + 1) - - def draw_kmi(self, display_keymaps, kc, km, kmi, layout, level): - map_type = kmi.map_type - - col = self.indented_layout(layout, level) - - if kmi.show_expanded: - col = col.column(align=True) - box = col.box() - else: - box = col.column() - - split = box.split(percentage=0.05) - - # header bar - row = split.row() - row.prop(kmi, "show_expanded", text="", emboss=False) - - row = split.row() - row.prop(kmi, "active", text="", emboss=False) - - if km.is_modal: - row.prop(kmi, "propvalue", text="") - else: - row.label(text=kmi.name) - - row = split.row() - row.prop(kmi, "map_type", text="") - if map_type == 'KEYBOARD': - row.prop(kmi, "type", text="", full_event=True) - elif map_type == 'MOUSE': - row.prop(kmi, "type", text="", full_event=True) - elif map_type == 'NDOF': - row.prop(kmi, "type", text="", full_event=True) - elif map_type == 'TWEAK': - subrow = row.row() - subrow.prop(kmi, "type", text="") - subrow.prop(kmi, "value", text="") - elif map_type == 'TIMER': - row.prop(kmi, "type", text="") - else: - row.label() - - if (not kmi.is_user_defined) and kmi.is_user_modified: - row.operator("wm.keyitem_restore", text="", icon='BACK').item_id = kmi.id - else: - row.operator("wm.keyitem_remove", text="", icon='X').item_id = kmi.id - - # Expanded, additional event settings - if kmi.show_expanded: - box = col.box() - - split = box.split(percentage=0.4) - sub = split.row() - - if km.is_modal: - sub.prop(kmi, "propvalue", text="") - else: - # One day... - #~ sub.prop_search(kmi, "idname", bpy.context.window_manager, "operators_all", text="") - sub.prop(kmi, "idname", text="") - - if map_type not in {'TEXTINPUT', 'TIMER'}: - sub = split.column() - subrow = sub.row(align=True) - - if map_type == 'KEYBOARD': - subrow.prop(kmi, "type", text="", event=True) - subrow.prop(kmi, "value", text="") - elif map_type in {'MOUSE', 'NDOF'}: - subrow.prop(kmi, "type", text="") - subrow.prop(kmi, "value", text="") - - subrow = sub.row() - subrow.scale_x = 0.75 - subrow.prop(kmi, "any") - subrow.prop(kmi, "shift") - subrow.prop(kmi, "ctrl") - subrow.prop(kmi, "alt") - subrow.prop(kmi, "oskey", text="Cmd") - subrow.prop(kmi, "key_modifier", text="", event=True) - - # Operator properties - box.template_keymap_item_properties(kmi) - - # Modal key maps attached to this operator - if not km.is_modal: - kmm = kc.keymaps.find_modal(kmi.idname) - if kmm: - self.draw_km(display_keymaps, kc, kmm, None, layout, level + 1) - layout.context_pointer_set("keymap", km) - - _EVENT_TYPES = set() - _EVENT_TYPE_MAP = {} - - def draw_filtered(self, display_keymaps, filter_type, filter_text, layout): - - if filter_type == 'NAME': - def filter_func(kmi): - return (filter_text in kmi.idname.lower() or - filter_text in kmi.name.lower()) - else: - if not self._EVENT_TYPES: - enum = bpy.types.Event.bl_rna.properties["type"].enum_items - self._EVENT_TYPES.update(enum.keys()) - self._EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key for key, item in enum.items()}) - - del enum - self._EVENT_TYPE_MAP.update({ - "`": 'ACCENT_GRAVE', - "*": 'NUMPAD_ASTERIX', - "/": 'NUMPAD_SLASH', - "RMB": 'RIGHTMOUSE', - "LMB": 'LEFTMOUSE', - "MMB": 'MIDDLEMOUSE', - }) - self._EVENT_TYPE_MAP.update({ - "%d" % i: "NUMPAD_%d" % i for i in range(9) - }) - # done with once off init - - filter_text_split = filter_text.strip() - filter_text_split = filter_text.split() - - # Modifier {kmi.attribute: name} mapping - key_mod = { - "ctrl": "ctrl", - "alt": "alt", - "shift": "shift", - "cmd": "oskey", - "oskey": "oskey", - "any": "any", - } - # KeyMapItem like dict, use for comparing against - # attr: state - kmi_test_dict = {} - - # initialize? - so if a if a kmi has a MOD assigned it wont show up. - #~ for kv in key_mod.values(): - #~ kmi_test_dict[kv] = False - - # altname: attr - for kk, kv in key_mod.items(): - if kk in filter_text_split: - filter_text_split.remove(kk) - kmi_test_dict[kv] = True - # whats left should be the event type - if len(filter_text_split) > 1: - return False - elif filter_text_split: - kmi_type = filter_text_split[0].upper() - - if kmi_type not in self._EVENT_TYPES: - # replacement table - kmi_type_test = self._EVENT_TYPE_MAP.get(kmi_type) - if kmi_type_test is None: - # print("Unknown Type:", kmi_type) - - # Partial match - for k, v in self._EVENT_TYPE_MAP.items(): - if kmi_type in k: - kmi_type_test = v - break - if kmi_type in v: - kmi_type_test = v - break - - if kmi_type_test is None: - return False - - kmi_type = kmi_type_test - del kmi_type_test - - kmi_test_dict["type"] = kmi_type - - # main filter func, runs many times - def filter_func(kmi): - for kk, ki in kmi_test_dict.items(): - if getattr(kmi, kk) != ki: - return False - return True - - for km, kc in display_keymaps: - km = km.active() - layout.context_pointer_set("keymap", km) - - filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)] - - if filtered_items: - col = layout.column() - - row = col.row() - row.label(text=km.name, icon='DOT') - - row.label() - row.label() - - if km.is_user_modified: - row.operator("wm.keymap_restore", text="Restore") - else: - row.label() - - for kmi in filtered_items: - self.draw_kmi(display_keymaps, kc, km, kmi, col, 1) - - # "Add New" at end of keymap item list - col = self.indented_layout(layout, 1) - subcol = col.split(percentage=0.2).column() - subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN') - return True - - def draw_hierarchy(self, display_keymaps, layout): - from bpy_extras import keyconfig_utils - for entry in keyconfig_utils.KM_HIERARCHY: - self.draw_entry(display_keymaps, entry, layout) - - def draw_keymaps(self, context, layout): - from bpy_extras import keyconfig_utils - - wm = context.window_manager - kc = wm.keyconfigs.user - spref = context.space_data - - col = layout.column() - sub = col.column() - - subsplit = sub.split() - subcol = subsplit.column() - - row = subcol.row(align=True) - - #~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:") - text = bpy.path.display_name(wm.keyconfigs.active.name) - if not text: - text = "Blender (default)" - row.menu("USERPREF_MT_keyconfigs", text=text) - row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMIN') - row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMOUT').remove_active = True - - #~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active) - #~ row.operator("wm.keyconfig_remove", text="", icon='X') - row.separator() - rowsub = row.split(align=True, percentage=0.33) - # postpone drawing into rowsub, so we can set alert! + # "Add New" at end of keymap item list + col = _indented_layout(col, level + 1) + subcol = col.split(percentage=0.2).column() + subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager, + icon='ZOOMIN') col.separator() - display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc) - filter_type = spref.filter_type - filter_text = spref.filter_text.strip() - if filter_text: - filter_text = filter_text.lower() - ok = self.draw_filtered(display_keymaps, filter_type, filter_text, col) + + # Child key maps + if children: + subcol = col.column() + row = subcol.row() + + for entry in children: + draw_entry(display_keymaps, entry, col, level + 1) + + +def draw_kmi(display_keymaps, kc, km, kmi, layout, level): + map_type = kmi.map_type + + col = _indented_layout(layout, level) + + if kmi.show_expanded: + col = col.column(align=True) + box = col.box() + else: + box = col.column() + + split = box.split(percentage=0.05) + + # header bar + row = split.row() + row.prop(kmi, "show_expanded", text="", emboss=False) + + row = split.row() + row.prop(kmi, "active", text="", emboss=False) + + if km.is_modal: + row.prop(kmi, "propvalue", text="") + else: + row.label(text=kmi.name) + + row = split.row() + row.prop(kmi, "map_type", text="") + if map_type == 'KEYBOARD': + row.prop(kmi, "type", text="", full_event=True) + elif map_type == 'MOUSE': + row.prop(kmi, "type", text="", full_event=True) + elif map_type == 'NDOF': + row.prop(kmi, "type", text="", full_event=True) + elif map_type == 'TWEAK': + subrow = row.row() + subrow.prop(kmi, "type", text="") + subrow.prop(kmi, "value", text="") + elif map_type == 'TIMER': + row.prop(kmi, "type", text="") + else: + row.label() + + if (not kmi.is_user_defined) and kmi.is_user_modified: + row.operator("wm.keyitem_restore", text="", icon='BACK').item_id = kmi.id + else: + row.operator("wm.keyitem_remove", text="", icon='X').item_id = kmi.id + + # Expanded, additional event settings + if kmi.show_expanded: + box = col.box() + + split = box.split(percentage=0.4) + sub = split.row() + + if km.is_modal: + sub.prop(kmi, "propvalue", text="") else: - self.draw_hierarchy(display_keymaps, col) - ok = True + # One day... + #~ sub.prop_search(kmi, "idname", bpy.context.window_manager, "operators_all", text="") + sub.prop(kmi, "idname", text="") - # go back and fill in rowsub - rowsub.prop(spref, "filter_type", text="") - rowsubsub = rowsub.row(align=True) - if not ok: - rowsubsub.alert = True - rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM') + if map_type not in {'TEXTINPUT', 'TIMER'}: + sub = split.column() + subrow = sub.row(align=True) + + if map_type == 'KEYBOARD': + subrow.prop(kmi, "type", text="", event=True) + subrow.prop(kmi, "value", text="") + elif map_type in {'MOUSE', 'NDOF'}: + subrow.prop(kmi, "type", text="") + subrow.prop(kmi, "value", text="") + + subrow = sub.row() + subrow.scale_x = 0.75 + subrow.prop(kmi, "any") + subrow.prop(kmi, "shift") + subrow.prop(kmi, "ctrl") + subrow.prop(kmi, "alt") + subrow.prop(kmi, "oskey", text="Cmd") + subrow.prop(kmi, "key_modifier", text="", event=True) + + # Operator properties + box.template_keymap_item_properties(kmi) + + # Modal key maps attached to this operator + if not km.is_modal: + kmm = kc.keymaps.find_modal(kmi.idname) + if kmm: + draw_km(display_keymaps, kc, kmm, None, layout, level + 1) + layout.context_pointer_set("keymap", km) + +_EVENT_TYPES = set() +_EVENT_TYPE_MAP = {} -if __name__ == "__main__": # only for live edit. - bpy.utils.register_module(__name__) +def draw_filtered(display_keymaps, filter_type, filter_text, layout): + + if filter_type == 'NAME': + def filter_func(kmi): + return (filter_text in kmi.idname.lower() or + filter_text in kmi.name.lower()) + else: + if not _EVENT_TYPES: + enum = bpy.types.Event.bl_rna.properties["type"].enum_items + _EVENT_TYPES.update(enum.keys()) + _EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key + for key, item in enum.items()}) + + del enum + _EVENT_TYPE_MAP.update({ + "`": 'ACCENT_GRAVE', + "*": 'NUMPAD_ASTERIX', + "/": 'NUMPAD_SLASH', + "RMB": 'RIGHTMOUSE', + "LMB": 'LEFTMOUSE', + "MMB": 'MIDDLEMOUSE', + }) + _EVENT_TYPE_MAP.update({ + "%d" % i: "NUMPAD_%d" % i for i in range(9) + }) + # done with once off init + + filter_text_split = filter_text.strip() + filter_text_split = filter_text.split() + + # Modifier {kmi.attribute: name} mapping + key_mod = { + "ctrl": "ctrl", + "alt": "alt", + "shift": "shift", + "cmd": "oskey", + "oskey": "oskey", + "any": "any", + } + # KeyMapItem like dict, use for comparing against + # attr: state + kmi_test_dict = {} + + # initialize? - so if a if a kmi has a MOD assigned it wont show up. + #~ for kv in key_mod.values(): + #~ kmi_test_dict[kv] = False + + # altname: attr + for kk, kv in key_mod.items(): + if kk in filter_text_split: + filter_text_split.remove(kk) + kmi_test_dict[kv] = True + # whats left should be the event type + if len(filter_text_split) > 1: + return False + elif filter_text_split: + kmi_type = filter_text_split[0].upper() + + if kmi_type not in _EVENT_TYPES: + # replacement table + kmi_type_test = _EVENT_TYPE_MAP.get(kmi_type) + if kmi_type_test is None: + # print("Unknown Type:", kmi_type) + + # Partial match + for k, v in _EVENT_TYPE_MAP.items(): + if kmi_type in k: + kmi_type_test = v + break + if kmi_type in v: + kmi_type_test = v + break + + if kmi_type_test is None: + return False + + kmi_type = kmi_type_test + del kmi_type_test + + kmi_test_dict["type"] = kmi_type + + # main filter func, runs many times + def filter_func(kmi): + for kk, ki in kmi_test_dict.items(): + if getattr(kmi, kk) != ki: + return False + return True + + for km, kc in display_keymaps: + km = km.active() + layout.context_pointer_set("keymap", km) + + filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)] + + if filtered_items: + col = layout.column() + + row = col.row() + row.label(text=km.name, icon='DOT') + + row.label() + row.label() + + if km.is_user_modified: + row.operator("wm.keymap_restore", text="Restore") + else: + row.label() + + for kmi in filtered_items: + draw_kmi(display_keymaps, kc, km, kmi, col, 1) + + # "Add New" at end of keymap item list + col = _indented_layout(layout, 1) + subcol = col.split(percentage=0.2).column() + subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN') + return True + + +def draw_hierarchy(display_keymaps, layout): + from bpy_extras import keyconfig_utils + for entry in keyconfig_utils.KM_HIERARCHY: + draw_entry(display_keymaps, entry, layout) + + +def draw_keymaps(context, layout): + from bpy_extras import keyconfig_utils + + wm = context.window_manager + kc = wm.keyconfigs.user + spref = context.space_data + + col = layout.column() + sub = col.column() + + subsplit = sub.split() + subcol = subsplit.column() + + row = subcol.row(align=True) + + #~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:") + text = bpy.path.display_name(wm.keyconfigs.active.name) + if not text: + text = "Blender (default)" + row.menu("USERPREF_MT_keyconfigs", text=text) + row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMIN') + row.operator("wm.keyconfig_preset_add", text="", icon='ZOOMOUT').remove_active = True + + #~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active) + #~ row.operator("wm.keyconfig_remove", text="", icon='X') + row.separator() + rowsub = row.split(align=True, percentage=0.33) + # postpone drawing into rowsub, so we can set alert! + + col.separator() + display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc) + filter_type = spref.filter_type + filter_text = spref.filter_text.strip() + if filter_text: + filter_text = filter_text.lower() + ok = draw_filtered(display_keymaps, filter_type, filter_text, col) + else: + draw_hierarchy(display_keymaps, col) + ok = True + + # go back and fill in rowsub + rowsub.prop(spref, "filter_type", text="") + rowsubsub = rowsub.row(align=True) + if not ok: + rowsubsub.alert = True + rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM') diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 20f998cd568..7fe8d334572 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -617,8 +617,8 @@ class VIEW3D_MT_select_edit_mesh(Menu): layout.separator() - layout.operator("mesh.select_less", text="Less") layout.operator("mesh.select_more", text="More") + layout.operator("mesh.select_less", text="Less") layout.separator() diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index a6e28b3df02..9260a106308 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1951,7 +1951,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D { ModifierData *md, *previewmd = NULL; float (*deformedVerts)[3] = NULL; - CustomDataMask mask, previewmask = 0; + CustomDataMask mask, previewmask = 0, append_mask = 0; DerivedMesh *dm, *orcodm = NULL; int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1); CDMaskLink *datamasks, *curr; @@ -2087,6 +2087,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } /* set the DerivedMesh to only copy needed data */ + mask |= append_mask; mask = curr->mask; /* CD_MASK_ORCO may have been cleared above */ DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX); @@ -2116,6 +2117,12 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D } } + /* In case of active preview modifier, make sure preview mask remains for following modifiers. */ + if ((md == previewmd) && (do_mod_wmcol)) { + DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL); + append_mask |= CD_MASK_PREVIEW_MLOOPCOL; + } + if (cage_r && i == cageIndex) { if (dm && deformedVerts) { *cage_r = CDDM_copy(dm); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 9d1c0e40d54..a668c6a6d7b 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1698,7 +1698,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) { DynamicPaintSurface *surface; - int update_normals = 0; + bool update_normals = false; /* loop through surfaces */ for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { @@ -1881,19 +1881,21 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, normal_short_to_float_v3(normal, mvert[i].no); madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height); } - update_normals = 1; + update_normals = true; } /* displace */ if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) { dynamicPaint_applySurfaceDisplace(surface, result); - update_normals = 1; + update_normals = true; } } } } - result->dirty |= DM_DIRTY_NORMALS; + if (update_normals) { + result->dirty |= DM_DIRTY_NORMALS; + } } /* make a copy of dm to use as brush data */ if (pmd->brush) { diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5b5d4f3c318..4dc1e9be7ed 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1573,7 +1573,10 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only) { if (lib == NULL || id->lib == lib) { if (id->lib) { - id_make_local(id, false); + /* for Make Local > All we should be calling id_make_local, + * but doing that breaks append (see #36003 and #36006), we + * we should make it work with all datablocks and id.us==0 */ + id_clear_lib_data(bmain, id); /* sets 'id->flag' */ /* why sort alphabetically here but not in * id_clear_lib_data() ? - campbell */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 802f467d168..780bd9733f5 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -447,7 +447,7 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in { ModifierData *tmp_md = NULL; - if (required_mode != eModifierMode_Realtime) + if ((required_mode & ~eModifierMode_Editmode) != eModifierMode_Realtime) return tmp_md; /* Find the latest modifier in stack generating preview. */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 9840852ad7e..c9be73c4bd4 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -4313,7 +4313,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra) /* SPH_SOLVER_CLASSICAL */ /* Apply SPH forces using classical algorithm (due to Gingold * and Monaghan). Note that, unlike double-density relaxation, - * this algorthim is separated into distinct loops. */ + * this algorithm is separated into distinct loops. */ #pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5) LOOP_DYNAMIC_PARTICLES { diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index ddf1c598a1c..78b1f50c2e8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -1452,7 +1452,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3 int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float i1[3], float i2[3]) { float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3]; - float d; + float d, div; sub_v3_v3v3(c, v3, v1); sub_v3_v3v3(a, v2, v1); @@ -1468,12 +1468,17 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], cross_v3_v3v3(ab, a, b); d = dot_v3v3(c, ab); + div = dot_v3v3(ab, ab); + /* test zero length line */ + if (UNLIKELY(div == 0.0f)) { + return 0; + } /* test if the two lines are coplanar */ - if (d > -0.000001f && d < 0.000001f) { + else if (d > -0.000001f && d < 0.000001f) { cross_v3_v3v3(cb, c, b); - mul_v3_fl(a, dot_v3v3(cb, ab) / dot_v3v3(ab, ab)); + mul_v3_fl(a, dot_v3v3(cb, ab) / div); add_v3_v3v3(i1, v1, a); copy_v3_v3(i2, i1); @@ -1518,7 +1523,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], float vi[3], float *r_lambda) { float a[3], b[3], c[3], ab[3], cb[3], ca[3], dir1[3], dir2[3]; - float d; + float d, div; sub_v3_v3v3(c, v3, v1); sub_v3_v3v3(a, v2, v1); @@ -1534,15 +1539,20 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3], cross_v3_v3v3(ab, a, b); d = dot_v3v3(c, ab); + div = dot_v3v3(ab, ab); + /* test zero length line */ + if (UNLIKELY(div == 0.0f)) { + return 0; + } /* test if the two lines are coplanar */ - if (d > -0.000001f && d < 0.000001f) { + else if (d > -0.000001f && d < 0.000001f) { float f1, f2; cross_v3_v3v3(cb, c, b); cross_v3_v3v3(ca, c, a); - f1 = dot_v3v3(cb, ab) / dot_v3v3(ab, ab); - f2 = dot_v3v3(ca, ab) / dot_v3v3(ab, ab); + f1 = dot_v3v3(cb, ab) / div; + f2 = dot_v3v3(ca, ab) / div; if (f1 >= 0 && f1 <= 1 && f2 >= 0 && f2 <= 1) diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index e6b5fc15f52..b3dd2f57523 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC operators/bmo_join_triangles.c operators/bmo_mesh_conv.c operators/bmo_mirror.c + operators/bmo_normals.c operators/bmo_poke.c operators/bmo_primitive.c operators/bmo_removedoubles.c diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index 8b5b95c5cae..a484bd2fa27 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -428,7 +428,7 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo float len_best = FLT_MAX; if (use_normals) - BLI_assert(fabsf(len_squared_v3(no) - 1.0f) < FLT_EPSILON); + BLI_ASSERT_UNIT_V3(no); for (el_store = eloops->first; el_store; el_store = el_store->next) { float len; diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index dc7c13b3fe0..61a326bbf97 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -721,17 +721,23 @@ void BM_editselection_plane(BMEditSelection *ese, float r_plane[3]) else if (ese->htype == BM_EDGE) { BMEdge *eed = (BMEdge *)ese->ele; - /* the plane is simple, it runs along the edge - * however selecting different edges can swap the direction of the y axis. - * this makes it less likely for the y axis of the manipulator - * (running along the edge).. to flip less often. - * at least its more predictable */ - if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */ - sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co); + if (BM_edge_is_boundary(eed)) { + sub_v3_v3v3(r_plane, eed->l->v->co, eed->l->next->v->co); } else { - sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co); + /* the plane is simple, it runs along the edge + * however selecting different edges can swap the direction of the y axis. + * this makes it less likely for the y axis of the manipulator + * (running along the edge).. to flip less often. + * at least its more predictable */ + if (eed->v2->co[1] > eed->v1->co[1]) { /* check which to do first */ + sub_v3_v3v3(r_plane, eed->v2->co, eed->v1->co); + } + else { + sub_v3_v3v3(r_plane, eed->v1->co, eed->v2->co); + } } + normalize_v3(r_plane); } else if (ese->htype == BM_FACE) { diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 7e4d5e06100..497c9e1c153 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -150,7 +150,6 @@ static BMOpDefine bmo_recalc_face_normals_def = { "recalc_face_normals", /* slots_in */ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, - {"use_face_tag", BMO_OP_SLOT_BOOL}, /* Tag faces that have been flipped */ {{'\0'}}, }, {{{'\0'}}}, /* no output */ diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 045997fb6be..6b124a3030a 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -189,7 +189,10 @@ static void bridge_loop_pair(BMesh *bm, ((BMVert *)(((LinkData *)lb_b->first)->data))->co, ((BMVert *)(((LinkData *)lb_b->last)->data))->co); - /* this isnt totally reliable but works well in most cases */ + /* make the directions point out from the normals, 'no' is used as a temp var */ + cross_v3_v3v3(no, dir_a, el_dir); cross_v3_v3v3(dir_a, no, el_dir); + cross_v3_v3v3(no, dir_b, el_dir); cross_v3_v3v3(dir_b, no, el_dir); + if (dot_v3v3(dir_a, dir_b) < 0.0f) { BM_edgeloop_flip(bm, el_store_b); } diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index f80eafd4135..bd0466ff499 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -62,22 +62,19 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e, EDGE_MARK); BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { if (BMO_elem_flag_test(bm, v, VERT_USED) == false) { + if (i == tote) { + goto cleanup; + } + BMO_elem_flag_enable(bm, v, VERT_USED); verts[i++] = v; - if (i == tote) { - break; - } } } - if (i > tote) { - break; - } } /* we have a different number of verts to edges */ if (i != tote) { - MEM_freeN(verts); - return; + goto cleanup; } /* loop over connected flagged edges and fill in faces, this is made slightly more @@ -156,5 +153,6 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT); } +cleanup: MEM_freeN(verts); } diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c new file mode 100644 index 00000000000..88a4d4478be --- /dev/null +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -0,0 +1,138 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * 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. + * + * Contributor(s): Joseph Eagar, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_normals.c + * \ingroup bmesh + * + * normal recalculation. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +/********* righthand faces implementation ****** */ + +#define FACE_VIS 1 +#define FACE_FLAG 2 + +/* + * put normal to the outside, and set the first direction flags in edges + * + * then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces + * this is in fact the 'select connected' + * + * in case all faces were not done: start over with 'find the ultimate ...' */ + +/* NOTE: BM_ELEM_TAG is used on faces to tell if they are flipped. */ + +void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) +{ + BMFace **fstack; + STACK_DECLARE(fstack); + const unsigned int tot_faces = BMO_slot_buffer_count(op->slots_in, "faces"); + unsigned int tot_touch = 0; + + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); + + fstack = MEM_mallocN(sizeof(*fstack) * tot_faces, __func__); + + while (tot_touch != tot_faces) { + BMOIter siter; + float f_len_best = -FLT_MAX; + BMFace *f, *f_start = NULL; + float f_start_cent[3]; + + /* find a starting face */ + BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { + float f_cent[3]; + float f_len_test; + + /* clear dirty flag */ + BM_elem_flag_disable(f, BM_ELEM_TAG); + + if (BMO_elem_flag_test(bm, f, FACE_VIS)) + continue; + + if (!f_start) f_start = f; + + BM_face_calc_center_bounds(f, f_cent); + + if ((f_len_test = len_squared_v3(f_cent)) > f_len_best) { + f_len_best = f_len_test; + f_start = f; + copy_v3_v3(f_start_cent, f_cent); + } + } + + /* check sanity (while loop ensures) */ + BLI_assert(f_start != NULL); + + /* make sure the starting face has the correct winding */ + if (dot_v3v3(f_start_cent, f_start->no) < 0.0f) { + BM_face_normal_flip(bm, f_start); + } + + /* now that we've found our starting face, make all connected faces + * have the same winding. this is done recursively, using a manual + * stack (if we use simple function recursion, we'd end up overloading + * the stack on large meshes). */ + STACK_INIT(fstack); + + STACK_PUSH(fstack, f_start); + BMO_elem_flag_enable(bm, f_start, FACE_VIS); + tot_touch++; + + while ((f = STACK_POP(fstack))) { + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + BMLoop *l_other = l->radial_next; + + if ((l_other == l) || l_other->radial_next != l) { + continue; + } + + if (BMO_elem_flag_test(bm, l_other->f, FACE_FLAG)) { + if (!BMO_elem_flag_test(bm, l_other->f, FACE_VIS)) { + BMO_elem_flag_enable(bm, l_other->f, FACE_VIS); + tot_touch++; + + + if (l_other->v == l->v) { + BM_face_normal_flip(bm, l_other->f); + } + + STACK_PUSH(fstack, l_other->f); + } + } + } + } + } + + MEM_freeN(fstack); +} diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 5e61b8ea7ea..2a0a7864499 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -278,131 +278,6 @@ void bmo_region_extend_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_ALL_NOLOOP, SEL_FLAG); } -/********* righthand faces implementation ****** */ - -#define FACE_VIS 1 -#define FACE_FLAG 2 -// #define FACE_MARK 4 /* UNUSED */ -#define FACE_FLIP 8 - -/* NOTE: these are the original recalc_face_normals comment in editmesh_mods.c, - * copied here for reference. */ - -/* based at a select-connected to witness loose objects */ - -/* count per edge the amount of faces - * find the ultimate left, front, upper face (not manhattan dist!!) - * also evaluate both triangle cases in quad, since these can be non-flat - * - * put normal to the outside, and set the first direction flags in edges - * - * then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces - * this is in fact the 'select connected' - * - * in case (selected) faces were not done: start over with 'find the ultimate ...' */ - -/* NOTE: this function uses recursion, which is a little unusual for a bmop - * function, but acceptable I think. */ - -/* NOTE: BM_ELEM_TAG is used on faces to tell if they are flipped. */ - -void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) -{ - BMIter liter, liter2; - BMOIter siter; - BMFace *f, *startf; - BMFace **fstack; - STACK_DECLARE(fstack); - BMLoop *l, *l2; - float maxx, maxx_test, cent[3]; - const bool use_flip = BMO_slot_bool_get(op->slots_in, "use_face_tag"); - - startf = NULL; - maxx = -1.0e10; - - BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); - - /* find a starting face */ - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - - /* clear dirty flag */ - BM_elem_flag_disable(f, BM_ELEM_TAG); - - if (BMO_elem_flag_test(bm, f, FACE_VIS)) - continue; - - if (!startf) startf = f; - - BM_face_calc_center_bounds(f, cent); - - if ((maxx_test = dot_v3v3(cent, cent)) > maxx) { - maxx = maxx_test; - startf = f; - } - } - - if (!startf) return; - - BM_face_calc_center_bounds(startf, cent); - - /* make sure the starting face has the correct winding */ - if (dot_v3v3(cent, startf->no) < 0.0f) { - BM_face_normal_flip(bm, startf); - BMO_elem_flag_toggle(bm, startf, FACE_FLIP); - - if (use_flip) - BM_elem_flag_toggle(startf, BM_ELEM_TAG); - } - - /* now that we've found our starting face, make all connected faces - * have the same winding. this is done recursively, using a manual - * stack (if we use simple function recursion, we'd end up overloading - * the stack on large meshes). */ - fstack = MEM_mallocN(sizeof(*fstack) * BMO_slot_buffer_count(op->slots_in, "faces"), __func__); - STACK_INIT(fstack); - STACK_PUSH(fstack, startf); - BMO_elem_flag_enable(bm, startf, FACE_VIS); - - while ((f = STACK_POP(fstack))) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) { - if (!BMO_elem_flag_test(bm, l2->f, FACE_FLAG) || l2 == l) - continue; - - if (!BMO_elem_flag_test(bm, l2->f, FACE_VIS)) { - BMO_elem_flag_enable(bm, l2->f, FACE_VIS); - - if (l2->v == l->v) { - BM_face_normal_flip(bm, l2->f); - - BMO_elem_flag_toggle(bm, l2->f, FACE_FLIP); - if (use_flip) - BM_elem_flag_toggle(l2->f, BM_ELEM_TAG); - } - else if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l->f, BM_ELEM_TAG)) { - if (use_flip) { - BM_elem_flag_disable(l->f, BM_ELEM_TAG); - BM_elem_flag_disable(l2->f, BM_ELEM_TAG); - } - } - - STACK_PUSH(fstack, l2->f); - } - } - } - } - - MEM_freeN(fstack); - - /* check if we have faces yet to do. if so, recurse */ - BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { - if (!BMO_elem_flag_test(bm, f, FACE_VIS)) { - bmo_recalc_face_normals_exec(bm, op); - break; - } - } -} - void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) { BMOIter siter; diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp index 39665b10f48..5006720f091 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp @@ -1284,7 +1284,7 @@ void DoubleEdgeMaskOperation::executePixel(float output[4], int x, int y, void * { float *buffer = (float *)data; int index = (y * this->getWidth() + x); - copy_v4_v4(output, buffer + index); + output[0] = buffer[index]; } void DoubleEdgeMaskOperation::deinitExecution() diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 13c1f2d5b2b..d480d41f5d6 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -84,39 +84,25 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name) return bone; } -/* v3d and rv3d are allowed to be NULL */ -void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d) +void add_primitive_bone(Object *obedit_arm, bool view_aligned) { - Object *obedit = scene->obedit; // XXX get from context - bArmature *arm = obedit->data; - float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; - EditBone *bone; + bArmature *arm = obedit_arm->data; + EditBone *bone; - /* Get inverse point for head and orientation for tail */ - invert_m4_m4(obedit->imat, obedit->obmat); - mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - copy_m3_m4(obmat, rv3d->viewmat); - else unit_m3(obmat); - - copy_m3_m4(viewmat, obedit->obmat); - mul_m3_m3m3(totmat, obmat, viewmat); - invert_m3_m3(imat, totmat); - - ED_armature_deselect_all(obedit, 0); + ED_armature_deselect_all(obedit_arm, 0); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; - copy_v3_v3(bone->head, curs); - - if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) - add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 + zero_v3(bone->head); + zero_v3(bone->tail); + + if (view_aligned) + bone->tail[1] = 1.0f; else - add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z + bone->tail[2] = 1.0f; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 3327d4a07e9..0f96e886ef3 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -2833,6 +2833,44 @@ void CURVE_OT_reveal(wmOperatorType *ot) /********************** subdivide operator *********************/ +static BezTriple *next_spline_bezier_point_get(Nurb *nu, BezTriple *bezt) +{ + BezTriple *nextbezt; + + if (bezt == nu->bezt + nu->pntsu - 1) { + if (nu->flagu & CU_NURB_CYCLIC) { + nextbezt = nu->bezt; + } + else { + nextbezt = NULL; + } + } + else { + nextbezt = bezt + 1; + } + + return nextbezt; +} + +static BPoint *next_spline_bpoint_get(Nurb *nu, BPoint *bp) +{ + BPoint *nextbp; + + if (bp == nu->bp + nu->pntsu - 1) { + if (nu->flagu & CU_NURB_CYCLIC) { + nextbp = nu->bp; + } + else { + nextbp = NULL; + } + } + else { + nextbp = bp + 1; + } + + return nextbp; +} + /** Divide the line segments associated with the currently selected * curve nodes (Bezier or NURB). If there are no valid segment * selections within the current selection, nothing happens. @@ -2842,7 +2880,7 @@ static void subdividenurb(Object *obedit, int number_cuts) Curve *cu = obedit->data; EditNurb *editnurb = cu->editnurb; Nurb *nu; - BezTriple *prevbezt, *bezt, *beztnew, *beztn; + BezTriple *bezt, *beztnew, *beztn; BPoint *bp, *prevbp, *bpnew, *bpn; float vec[15]; int a, b, sel, amount, *usel, *vsel, i; @@ -2853,25 +2891,25 @@ static void subdividenurb(Object *obedit, int number_cuts) for (nu = editnurb->nurbs.first; nu; nu = nu->next) { amount = 0; if (nu->type == CU_BEZIER) { + BezTriple *nextbezt; + /* * Insert a point into a 2D Bezier curve. * Endpoints are preserved. Otherwise, all selected and inserted points are * newly created. Old points are discarded. */ /* count */ - if (nu->flagu & CU_NURB_CYCLIC) { - a = nu->pntsu; - bezt = nu->bezt; - prevbezt = bezt + (a - 1); - } - else { - a = nu->pntsu - 1; - prevbezt = nu->bezt; - bezt = prevbezt + 1; - } + a = nu->pntsu; + bezt = nu->bezt; while (a--) { - if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt) ) amount += number_cuts; - prevbezt = bezt; + nextbezt = next_spline_bezier_point_get(nu, bezt); + if (nextbezt == NULL) { + break; + } + + if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) { + amount += number_cuts; + } bezt++; } @@ -2879,35 +2917,32 @@ static void subdividenurb(Object *obedit, int number_cuts) /* insert */ beztnew = (BezTriple *)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb"); beztn = beztnew; - if (nu->flagu & CU_NURB_CYCLIC) { - a = nu->pntsu; - bezt = nu->bezt; - prevbezt = bezt + (a - 1); - } - else { - a = nu->pntsu - 1; - prevbezt = nu->bezt; - bezt = prevbezt + 1; - } + a = nu->pntsu; + bezt = nu->bezt; while (a--) { - memcpy(beztn, prevbezt, sizeof(BezTriple)); - keyIndex_updateBezt(editnurb, prevbezt, beztn, 1); + memcpy(beztn, bezt, sizeof(BezTriple)); + keyIndex_updateBezt(editnurb, bezt, beztn, 1); beztn++; - if (BEZSELECTED_HIDDENHANDLES(cu, prevbezt) && BEZSELECTED_HIDDENHANDLES(cu, bezt)) { + nextbezt = next_spline_bezier_point_get(nu, bezt); + if (nextbezt == NULL) { + break; + } + + if (BEZSELECTED_HIDDENHANDLES(cu, bezt) && BEZSELECTED_HIDDENHANDLES(cu, nextbezt)) { float prevvec[3][3]; - memcpy(prevvec, prevbezt->vec, sizeof(float) * 9); + memcpy(prevvec, bezt->vec, sizeof(float) * 9); for (i = 0; i < number_cuts; i++) { factor = 1.0f / (number_cuts + 1 - i); - memcpy(beztn, bezt, sizeof(BezTriple)); + memcpy(beztn, nextbezt, sizeof(BezTriple)); /* midpoint subdividing */ interp_v3_v3v3(vec, prevvec[1], prevvec[2], factor); - interp_v3_v3v3(vec + 3, prevvec[2], bezt->vec[0], factor); - interp_v3_v3v3(vec + 6, bezt->vec[0], bezt->vec[1], factor); + interp_v3_v3v3(vec + 3, prevvec[2], nextbezt->vec[0], factor); + interp_v3_v3v3(vec + 6, nextbezt->vec[0], nextbezt->vec[1], factor); interp_v3_v3v3(vec + 9, vec, vec + 3, factor); interp_v3_v3v3(vec + 12, vec + 3, vec + 6, factor); @@ -2920,24 +2955,18 @@ static void subdividenurb(Object *obedit, int number_cuts) copy_v3_v3(beztn->vec[2], vec + 12); /* handle of next bezt */ if (a == 0 && i == number_cuts - 1 && (nu->flagu & CU_NURB_CYCLIC)) { copy_v3_v3(beztnew->vec[0], vec + 6); } - else { copy_v3_v3(bezt->vec[0], vec + 6); } + else { copy_v3_v3(nextbezt->vec[0], vec + 6); } - beztn->radius = (prevbezt->radius + bezt->radius) / 2; - beztn->weight = (prevbezt->weight + bezt->weight) / 2; + beztn->radius = (bezt->radius + nextbezt->radius) / 2; + beztn->weight = (bezt->weight + nextbezt->weight) / 2; memcpy(prevvec, beztn->vec, sizeof(float) * 9); beztn++; } } - prevbezt = bezt; bezt++; } - /* last point */ - if ((nu->flagu & CU_NURB_CYCLIC) == 0) { - memcpy(beztn, prevbezt, sizeof(BezTriple)); - keyIndex_updateBezt(editnurb, prevbezt, beztn, 1); - } MEM_freeN(nu->bezt); nu->bezt = beztnew; @@ -2947,6 +2976,8 @@ static void subdividenurb(Object *obedit, int number_cuts) } } /* End of 'if (nu->type == CU_BEZIER)' */ else if (nu->pntsv == 1) { + BPoint *nextbp; + /* * All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves * are handled together with the regular NURB plane division, as it @@ -2954,19 +2985,17 @@ static void subdividenurb(Object *obedit, int number_cuts) * stable... nzc 30-5-'00 */ /* count */ - if (nu->flagu & CU_NURB_CYCLIC) { - a = nu->pntsu; - bp = nu->bp; - prevbp = bp + (a - 1); - } - else { - a = nu->pntsu - 1; - prevbp = nu->bp; - bp = prevbp + 1; - } + a = nu->pntsu; + bp = nu->bp; while (a--) { - if ( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount += number_cuts; - prevbp = bp; + nextbp = next_spline_bpoint_get(nu, bp); + if (nextbp == NULL) { + break; + } + + if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) { + amount += number_cuts; + } bp++; } @@ -2975,39 +3004,33 @@ static void subdividenurb(Object *obedit, int number_cuts) bpnew = (BPoint *)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2"); bpn = bpnew; - if (nu->flagu & CU_NURB_CYCLIC) { - a = nu->pntsu; - bp = nu->bp; - prevbp = bp + (a - 1); - } - else { - a = nu->pntsu - 1; - prevbp = nu->bp; - bp = prevbp + 1; - } + a = nu->pntsu; + bp = nu->bp; + while (a--) { - memcpy(bpn, prevbp, sizeof(BPoint)); - keyIndex_updateBP(editnurb, prevbp, bpn, 1); + /* Copy "old" point. */ + memcpy(bpn, bp, sizeof(BPoint)); + keyIndex_updateBP(editnurb, bp, bpn, 1); bpn++; - if ((bp->f1 & SELECT) && (prevbp->f1 & SELECT)) { + nextbp = next_spline_bpoint_get(nu, bp); + if (nextbp == NULL) { + break; + } + + if ((bp->f1 & SELECT) && (nextbp->f1 & SELECT)) { // printf("*** subdivideNurb: insert 'linear' point\n"); for (i = 0; i < number_cuts; i++) { factor = (float)(i + 1) / (number_cuts + 1); - memcpy(bpn, bp, sizeof(BPoint)); - interp_v4_v4v4(bpn->vec, prevbp->vec, bp->vec, factor); + memcpy(bpn, nextbp, sizeof(BPoint)); + interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor); bpn++; } } - prevbp = bp; bp++; } - if ((nu->flagu & CU_NURB_CYCLIC) == 0) { /* last point */ - memcpy(bpn, prevbp, sizeof(BPoint)); - keyIndex_updateBP(editnurb, prevbp, bpn, 1); - } MEM_freeN(nu->bp); nu->bp = bpnew; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 3367dcb9c4c..801fa12d444 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -132,7 +132,7 @@ EditBone *ED_armature_bone_get_mirrored(struct ListBase *edbo, EditBone *ebo); / void ED_armature_sync_selection(struct ListBase *edbo); void ED_armature_validate_active(struct bArmature *arm); -void add_primitive_bone(struct Scene *scene, struct View3D *v3d, struct RegionView3D *rv3d); +void add_primitive_bone(struct Object *obedit_arm, bool view_aligned); struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name); void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone); bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 807d94b56b0..51d5d42394c 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -233,6 +233,7 @@ void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); #define WEIGHT_ADD 2 #define WEIGHT_SUBTRACT 3 +bool ED_vgroup_sync_from_pose(struct Object *ob); struct bDeformGroup *ED_vgroup_add(struct Object *ob); struct bDeformGroup *ED_vgroup_add_name(struct Object *ob, const char *name); void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index b997d0ef6a0..b566fd360b6 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -534,7 +534,8 @@ enum { BUT_GET_TIP, BUT_GET_RNA_TIP, BUT_GET_RNAENUM_TIP, - BUT_GET_OP_KEYMAP + BUT_GET_OP_KEYMAP, + BUT_GET_PROP_KEYMAP }; typedef struct uiStringInfo { diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 19eb978a01e..9ac499fc94b 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -901,6 +901,114 @@ static bool ui_but_event_operator_string(const bContext *C, uiBut *but, char *bu return found; } +static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, char *buf, const size_t buf_len) +{ + /* context toggle operator names to check... */ + const char *ctx_toggle_opnames[] = { + "WM_OT_context_toggle", + "WM_OT_context_toggle_enum", + "WM_OT_context_cycle_int", + "WM_OT_context_cycle_enum", + "WM_OT_context_cycle_array", + "WM_OT_context_menu_enum", + NULL + }; + const size_t num_ops = sizeof(ctx_toggle_opnames) / sizeof(const char *); + + bool found = false; + + /* this version is only for finding hotkeys for properties (which get set via context using operators) */ + if (but->rnaprop) { + /* to avoid massive slowdowns on property panels, for now, we only check the + * hotkeys for Editor / Scene settings... + * + * TODO: userpref settings? + */ + // TODO: value (for enum stuff)? + char *data_path = NULL; + + if (but->rnapoin.id.data) { + ID *id = but->rnapoin.id.data; + + if (GS(id->name) == ID_SCR) { + /* screen/editor property + * NOTE: in most cases, there is actually no info for backwards tracing + * how to get back to ID from the editor data we may be dealing with + */ + if (RNA_struct_is_a(but->rnapoin.type, &RNA_Space)) { + /* data should be directly on here... */ + data_path = BLI_sprintfN("space_data.%s", RNA_property_identifier(but->rnaprop)); + } + else { + /* special exceptions for common nested data in editors... */ + if (RNA_struct_is_a(but->rnapoin.type, &RNA_DopeSheet)) { + /* dopesheet filtering options... */ + data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop)); + } + } + } + else if (GS(id->name) == ID_SCE) { + if (RNA_struct_is_a(but->rnapoin.type, &RNA_ToolSettings)) { + /* toolsettings property + * NOTE: toolsettings is usually accessed directly (i.e. not through scene) + */ + data_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); + } + else { + /* scene property */ + char *path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); + + if (path) { + data_path = BLI_sprintfN("scene.%s", path); + MEM_freeN(path); + } + else { + printf("ERROR in %s(): Couldn't get path for scene property - %s\n", + __func__, RNA_property_identifier(but->rnaprop)); + } + } + } + else { + //puts("other id"); + } + + //printf("prop shortcut: '%s' (%s)\n", RNA_property_identifier(but->rnaprop), data_path); + } + + /* we have a datapath! */ + if (data_path) { + size_t i; + + /* create a property to host the "datapath" property we're sending to the operators */ + IDProperty *prop_path; + IDProperty *prop_path_value; + + IDPropertyTemplate val = {0}; + prop_path = IDP_New(IDP_GROUP, &val, __func__); + prop_path_value = IDP_NewString(data_path, "data_path", strlen(data_path) + 1); /* len + 1, or else will be truncated */ + IDP_AddToGroup(prop_path, prop_path_value); + + /* check each until one works... */ + for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) { + //printf("\t%s\n", ctx_toggle_opnames[i]); + if (WM_key_event_operator_string(C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false, + buf, buf_len)) + { + found = true; + break; + } + } + + /* cleanup */ + IDP_FreeProperty(prop_path); + MEM_freeN(prop_path); + MEM_freeN(data_path); + } + } + + return found; +} + static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) { uiBut *but; @@ -915,6 +1023,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { ui_but_add_shortcut(but, buf, FALSE); } + else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { + ui_but_add_shortcut(but, buf, FALSE); + } } } @@ -4011,6 +4122,13 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...) } } } + else if (type == BUT_GET_PROP_KEYMAP) { + /* for properties that are bound to one of the context cycle, etc. keys... */ + char buf[128]; + if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { + tmp = BLI_strdup(buf); + } + } si->strinfo = tmp; } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 4c1ad2e41c4..342c0569f41 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1852,7 +1852,6 @@ enum { static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const int mode) { - char buf[UI_MAX_DRAW_STR] = {0}; char *str, *p, *pbuf; int x; bool changed = false; @@ -1868,6 +1867,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in p = pbuf = WM_clipboard_text_get(0); if (p && p[0]) { + char buf[UI_MAX_DRAW_STR] = {0}; unsigned int y; buf_len = 0; while (*p && *p != '\r' && *p != '\n' && buf_len < UI_MAX_DRAW_STR - 1) { @@ -1904,14 +1904,12 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in /* cut & copy */ else if (ELEM(mode, UI_TEXTEDIT_COPY, UI_TEXTEDIT_CUT)) { /* copy the contents to the copypaste buffer */ - for (x = but->selsta; x <= but->selend; x++) { - if (x == but->selend) - buf[x] = '\0'; - else - buf[(x - but->selsta)] = str[x]; - } + int sellen = but->selend - but->selsta; + char *buf = MEM_mallocN(sizeof(char) * (sellen + 1), "ui_textedit_copypaste"); + BLI_strncpy(buf, str + but->selsta, sellen + 1); WM_clipboard_text_set(buf, 0); + MEM_freeN(buf); /* for cut only, delete the selection afterwards */ if (mode == UI_TEXTEDIT_CUT) { diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index fbe23b1a1ed..9558baf0334 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -439,6 +439,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL}; uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL}; uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; + uiStringInfo prop_keymap = {BUT_GET_PROP_KEYMAP, NULL}; uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL}; uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL}; @@ -448,7 +449,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) /* create tooltip data */ data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - uiButGetStrInfo(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &rna_struct, &rna_prop, NULL); + uiButGetStrInfo(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL); /* special case, enum rna buttons only have enum item description, * use general enum description too before the specific one */ @@ -480,6 +481,13 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) data->color_id[data->totline] = UI_TIP_LC_NORMAL; data->totline++; } + + /* Property context-toggle shortcut */ + if (prop_keymap.strinfo) { + BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Shortcut: %s"), prop_keymap.strinfo); + data->color_id[data->totline] = UI_TIP_LC_NORMAL; + data->totline++; + } if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) { /* full string */ @@ -614,6 +622,8 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) MEM_freeN(enum_tip.strinfo); if (op_keymap.strinfo) MEM_freeN(op_keymap.strinfo); + if (prop_keymap.strinfo) + MEM_freeN(prop_keymap.strinfo); if (rna_struct.strinfo) MEM_freeN(rna_struct.strinfo); if (rna_prop.strinfo) diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index becffb64ae6..32d3d274b47 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -2094,8 +2094,7 @@ void init_userdef_do_versions(void) if (U.ndof_sensitivity == 0.0f) { U.ndof_sensitivity = 1.0f; - U.ndof_flag = NDOF_LOCK_HORIZON | - NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE; + U.ndof_flag = (NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE); } if (U.ndof_orbit_sensitivity == 0.0f) { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 2fa6812d131..2c721a0a9dc 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1066,7 +1066,7 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) /* doflip has to do with bmesh_rationalize_normals, it's an internal * thing */ - if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf use_face_tag=%b", BM_ELEM_SELECT, true)) + if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) return OPERATOR_CANCELLED; if (RNA_boolean_get(op->ptr, "inside")) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 3d5db18c546..f911495d5b4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -657,12 +657,12 @@ void OBJECT_OT_text_add(wmOperatorType *ot) static int object_armature_add_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); - View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); bool newob = false; bool enter_editmode; unsigned int layer; float loc[3], rot[3]; + bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED); if (!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; @@ -681,8 +681,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - /* v3d and rv3d are allowed to be NULL */ - add_primitive_bone(CTX_data_scene(C), v3d, rv3d); + add_primitive_bone(obedit, view_aligned); /* userdef */ if (newob && !enter_editmode) diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 909b70c8d3c..581c3d25730 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -109,6 +109,22 @@ static Lattice *vgroup_edit_lattice(Object *ob) return (lt->editlatt) ? lt->editlatt->latt : lt; } +bool ED_vgroup_sync_from_pose(Object *ob) +{ + Object *armobj = BKE_object_pose_armature_get(ob); + if (armobj && (armobj->mode & OB_MODE_POSE)) { + struct bArmature *arm = armobj->data; + if (arm->act_bone) { + int def_num = defgroup_name_index(ob, arm->act_bone->name); + if (def_num != -1) { + ob->actdef = def_num + 1; + return true; + } + } + } + return false; +} + bool ED_vgroup_object_is_edit_mode(Object *ob) { if (ob->type == OB_MESH) @@ -749,10 +765,12 @@ static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGro unsigned int f_index; float weight, tmp_weight[4], tmp_co[3], normal[3], tmp_mat[4][4], dist_v1, dist_v2, dist_v3, dist_v4; const int use_vert_sel = vertex_group_use_vert_sel(ob_dst); + bool is_dg_dst_new = false; /* Ensure vertex group on target.*/ if ((dg_dst = defgroup_find_name(ob_dst, dg_src->name)) == NULL) { dg_dst = BKE_defgroup_new(ob_dst, dg_src->name); + is_dg_dst_new = true; } /* Get meshes.*/ @@ -804,7 +822,10 @@ static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGro if (ob_dst == ob_src || dv_tot_dst == 0 || dv_tot_dst != dv_tot_src || dv_array_src == NULL || dv_array_dst == NULL) { - ED_vgroup_delete(ob_dst, defgroup_find_name(ob_dst, dg_dst->name)); + if (is_dg_dst_new) { + ED_vgroup_delete(ob_dst, dg_dst); + } + if (dv_array_src) MEM_freeN(dv_array_src); if (dv_array_dst) MEM_freeN(dv_array_dst); dmesh_src->release(dmesh_src); @@ -901,18 +922,16 @@ static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGro project_v3_plane(tmp_co, normal, mv_src[mf->v1].co); /* Interpolate weights over face.*/ - f_index = mf->v4 ? 3 : 2; - if (f_index == 3) { - interp_weights_face_v3(tmp_weight, mv_src[mf->v1].co, mv_src[mf->v2].co, - mv_src[mf->v3].co, mv_src[mf->v4].co, tmp_co); - } - else { - interp_weights_face_v3(tmp_weight, mv_src[mf->v1].co, mv_src[mf->v2].co, - mv_src[mf->v3].co, NULL, tmp_co); - } + interp_weights_face_v3(tmp_weight, + mv_src[mf->v1].co, + mv_src[mf->v2].co, + mv_src[mf->v3].co, + mf->v4 ? mv_src[mf->v4].co : NULL, + tmp_co); /* Get weights from face.*/ - weight = 0; + f_index = mf->v4 ? 3 : 2; + weight = 0.0f; do { v_index = (&mf->v1)[f_index]; weight += tmp_weight[f_index] * defvert_find_weight(dv_array_src[v_index], index_src); @@ -920,7 +939,7 @@ static bool ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGro /* Copy weight that are not NULL including weight value 0. In relevant cases, existing weights are * overwritten prior to this. See the "Clear weights." step above.*/ - if (weight > 0) { + if (weight > 0.0f) { dw_dst = defvert_verify_index(*dv_dst, index_dst); vgroup_transfer_weight(&dw_dst->weight, weight, replace_mode); } @@ -2910,13 +2929,13 @@ static int vertex_group_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib - && data && !data->lib - && OB_TYPE_SUPPORT_VGROUP(ob->type) - && BLI_countlist(&ob->defbase) > 0 ); + return (ob && !ob->id.lib && + data && !data->lib && + OB_TYPE_SUPPORT_VGROUP(ob->type) && + ob->defbase.first); } -static int vertex_group_can_add_poll(bContext *C) +static int vertex_group_supported_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; @@ -2928,13 +2947,13 @@ static int vertex_group_mesh_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib - && data && !data->lib - && ob->type == OB_MESH - && BLI_countlist(&ob->defbase) > 0 ); + return (ob && !ob->id.lib && + data && !data->lib && + ob->type == OB_MESH && + ob->defbase.first); } -static int vertex_group_mesh_can_add_poll(bContext *C) +static int vertex_group_mesh_supported_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; @@ -3026,7 +3045,7 @@ void OBJECT_OT_vertex_group_add(wmOperatorType *ot) ot->description = "Add a new vertex group to the active object"; /* api callbacks */ - ot->poll = vertex_group_can_add_poll; + ot->poll = vertex_group_supported_poll; ot->exec = vertex_group_add_exec; /* flags */ @@ -3764,6 +3783,10 @@ static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob_act = CTX_data_active_object(C); + + bDeformGroup *dg_act = BLI_findlink(&ob_act->defbase, (ob_act->actdef - 1)); + char dg_act_name[MAX_VGROUP_NAME]; /* may be freed so copy */ + int fail = 0; bool change = false; @@ -3771,6 +3794,17 @@ static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) WT_Method method = RNA_enum_get(op->ptr, "method"); WT_ReplaceMode replace_mode = RNA_enum_get(op->ptr, "replace_mode"); + if (vertex_group_mode == WT_REPLACE_ACTIVE_VERTEX_GROUP) { + if (!dg_act) { + BKE_report(op->reports, RPT_WARNING, "Failed, active object has no active groups"); + return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel*/ + } + } + + if (dg_act) { + BLI_strncpy(dg_act_name, dg_act->name, sizeof(dg_act_name)); + } + /* Macro to loop through selected objects and perform operation depending on function, option and method.*/ CTX_DATA_BEGIN (C, Object *, ob_src, selected_editable_objects) { @@ -3782,8 +3816,11 @@ static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) continue; } else if (ob_src->type != OB_MESH) { - BKE_reportf(op->reports, RPT_WARNING, - "Skipping object '%s' only copying from meshes is supported", ob_src->id.name + 2); + /* armatures can be in pose mode so ignore them */ + if (ob_src->type != OB_ARMATURE) { + BKE_reportf(op->reports, RPT_WARNING, + "Skipping object '%s' only copying from meshes is supported", ob_src->id.name + 2); + } continue; } @@ -3792,7 +3829,14 @@ static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) case WT_REPLACE_ACTIVE_VERTEX_GROUP: { bDeformGroup *dg_src; - dg_src = BLI_findlink(&ob_src->defbase, ob_src->actdef - 1); + dg_src = defgroup_find_name(ob_src, dg_act_name); + + if (dg_src == NULL) { + BKE_reportf(op->reports, RPT_WARNING, + "Skipping object '%s' no group '%s' found", ob_src->id.name + 2, dg_act_name); + continue; + } + if (ed_vgroup_transfer_weight(ob_act, ob_src, dg_src, scene, method, replace_mode, op)) { change = true; } @@ -3823,14 +3867,30 @@ static int vertex_group_transfer_weight_exec(bContext *C, wmOperator *op) CTX_DATA_END; if (change) { + + /* possible the active vertex group changed because of adding/removing */ + /* note!, dg_act may be realloc'd, only check its not NULL */ + if (dg_act) { + ED_vgroup_select_by_name(ob_act, dg_act_name); + } + else { + ED_vgroup_sync_from_pose(ob_act); + } + /* Event notifiers for correct display of data.*/ + + DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_act); /* for buttons */ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob_act); return OPERATOR_FINISHED; } else { - BKE_report(op->reports, RPT_WARNING, "Failed, no other selected objects with vertex groups found."); - return OPERATOR_CANCELLED; + if (op->reports->list.first == NULL) { + BKE_report(op->reports, RPT_WARNING, "Failed, no other selected objects with vertex groups found."); + } + + return OPERATOR_FINISHED; /* to get the chance to make changes in the redo panel */ } } @@ -3843,7 +3903,7 @@ void OBJECT_OT_vertex_group_transfer_weight(wmOperatorType *ot) ot->description = "Transfer weight paint to active from selected mesh"; /* API callbacks.*/ - ot->poll = vertex_group_mesh_can_add_poll; + ot->poll = vertex_group_mesh_supported_poll; ot->exec = vertex_group_transfer_weight_exec; /* Flags.*/ @@ -3851,7 +3911,7 @@ void OBJECT_OT_vertex_group_transfer_weight(wmOperatorType *ot) /* Properties.*/ /* TODO, use vgroup_operator_subset_select_props for group_select_mode */ - ot->prop = RNA_def_enum(ot->srna, "group_select_mode", WT_vertex_group_mode_item, WT_REPLACE_ACTIVE_VERTEX_GROUP, "Group", ""); + ot->prop = RNA_def_enum(ot->srna, "group_select_mode", WT_vertex_group_mode_item, WT_REPLACE_ALL_VERTEX_GROUPS, "Group", ""); ot->prop = RNA_def_enum(ot->srna, "method", WT_method_item, WT_BY_NEAREST_FACE, "Method", ""); ot->prop = RNA_def_enum(ot->srna, "replace_mode", WT_replace_mode_item, WT_REPLACE_ALL_WEIGHTS, "Replace", ""); } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index a891524b5c6..b7bd061d14a 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2047,8 +2047,6 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ DAG_id_tag_update(&me->id, 0); if (ob->mode & OB_MODE_WEIGHT_PAINT) { - Object *par; - if (wp == NULL) wp = scene->toolsettings->wpaint = new_vpaint(1); @@ -2057,14 +2055,7 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ mesh_octree_table(ob, NULL, NULL, 's'); - /* verify if active weight group is also active bone */ - par = modifiers_isDeformedByArmature(ob); - if (par && (par->mode & OB_MODE_POSE)) { - bArmature *arm = par->data; - - if (arm->act_bone) - ED_vgroup_select_by_name(ob, arm->act_bone->name); - } + ED_vgroup_sync_from_pose(ob); } else { mesh_octree_table(NULL, NULL, NULL, 'e'); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index a845f8e525c..fa39ccf4bca 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1271,13 +1271,8 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima, /* check for empty path */ if (guess_path && simopts->filepath[0] == 0) { - if ((G.ima[0] == '/') && (G.ima[1] == '/') && (G.ima[2] == '\0')) { - BLI_strncpy(simopts->filepath, "//untitled", FILE_MAX); - } - else { - BLI_strncpy(simopts->filepath, G.ima, FILE_MAX); - } - BLI_path_abs(simopts->filepath, G.main->name); + BLI_snprintf(simopts->filepath, sizeof(simopts->filepath), "//%s", ima->id.name + 2); + BLI_path_abs(simopts->filepath, STREQ(G.ima, "//") ? G.main->name : G.ima); } /* color management */ diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 135fddfd348..ff7220ea22d 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -866,7 +866,7 @@ static int cut_seq_list(Scene *scene, ListBase *slist, int cutframe, return (seq_first_new != NULL); } -static bool insert_gap(Scene *scene, int gap, int cfra) +static bool sequence_offset_after_frame(Scene *scene, const int delta, const int cfra) { Sequence *seq; Editing *ed = BKE_sequencer_editing_get(scene, FALSE); @@ -876,15 +876,13 @@ static bool insert_gap(Scene *scene, int gap, int cfra) if (ed == NULL) return 0; - SEQP_BEGIN (ed, seq) - { + for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->startdisp >= cfra) { - seq->start += gap; + BKE_sequence_translate(scene, seq, delta); BKE_sequence_calc(scene, seq); done = true; } } - SEQ_END return done; } @@ -1017,7 +1015,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) else if (BKE_sequencer_evaluate_frame(scene, cfra) == 0) { done = true; while (BKE_sequencer_evaluate_frame(scene, cfra) == 0) { - done = insert_gap(scene, -1, cfra); + done = sequence_offset_after_frame(scene, -1, cfra); if (done == false) break; } if (done == false || do_all == false) break; @@ -1054,7 +1052,7 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); int frames = RNA_int_get(op->ptr, "frames"); - insert_gap(scene, frames, CFRA); + sequence_offset_after_frame(scene, frames, CFRA); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 66ae7f6f8ac..eeacaab464c 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -3020,7 +3020,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, BMEdge *eed_act = NULL; BMVert *eve_act = NULL; - if (cageDM) BLI_assert(!(cageDM->dirty & DM_DIRTY_NORMALS)); + // if (cageDM) BLI_assert(!(cageDM->dirty & DM_DIRTY_NORMALS)); if (finalDM) BLI_assert(!(finalDM->dirty & DM_DIRTY_NORMALS)); if (em->bm->selected.last) { diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5ad5636bb21..bf81e0ac766 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1676,9 +1676,9 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar) */ UI_ThemeColorShade(TH_TEXT_HI, -50); #ifdef WITH_INTERNATIONAL - BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, sizeof(printable)); + BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #else - BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable)); + BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); #endif /* autokey recording icon... */ diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp index e44dfdf0bae..dd678ee6fbd 100644 --- a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp +++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp @@ -79,6 +79,26 @@ ContextFunctions_get_canvas_height(PyObject *self) return PyLong_FromLong(ContextFunctions::GetCanvasHeightCF()); } +static char ContextFunctions_get_border___doc__[] = +".. method:: get_border()\n" +"\n" +" Returns the border.\n" +"\n" +" :return: A tuple of 4 numbers (xmin, ymin, xmax, ymax).\n" +" :rtype: tuple\n"; + +static PyObject * +ContextFunctions_get_border(PyObject *self) +{ + BBox border(ContextFunctions::GetBorderCF()); + PyObject *v = PyTuple_New(4); + PyTuple_SET_ITEM(v, 0, PyLong_FromLong(border.getMin().x())); + PyTuple_SET_ITEM(v, 1, PyLong_FromLong(border.getMin().y())); + PyTuple_SET_ITEM(v, 2, PyLong_FromLong(border.getMax().x())); + PyTuple_SET_ITEM(v, 3, PyLong_FromLong(border.getMax().y())); + return v; +} + static char ContextFunctions_load_map___doc__[] = ".. function:: load_map(file_name, map_name, num_levels=4, sigma=1.0)\n" "\n" @@ -232,6 +252,8 @@ static PyMethodDef module_functions[] = { ContextFunctions_get_canvas_width___doc__}, {"get_canvas_height", (PyCFunction)ContextFunctions_get_canvas_height, METH_NOARGS, ContextFunctions_get_canvas_height___doc__}, + {"get_border", (PyCFunction)ContextFunctions_get_border, METH_NOARGS, + ContextFunctions_get_border___doc__}, {"load_map", (PyCFunction)ContextFunctions_load_map, METH_VARARGS | METH_KEYWORDS, ContextFunctions_load_map___doc__}, {"read_map_pixel", (PyCFunction)ContextFunctions_read_map_pixel, METH_VARARGS | METH_KEYWORDS, diff --git a/source/blender/freestyle/intern/stroke/Canvas.h b/source/blender/freestyle/intern/stroke/Canvas.h index 07aa171534a..038b4b3af0f 100644 --- a/source/blender/freestyle/intern/stroke/Canvas.h +++ b/source/blender/freestyle/intern/stroke/Canvas.h @@ -195,6 +195,7 @@ public: virtual int width() const = 0; virtual int height() const = 0; + virtual BBox border() const = 0; virtual BBox scene3DBBox() const = 0; inline const StrokeRenderer *renderer() const diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp index 42d27a0e5c3..052a6804815 100644 --- a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp +++ b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp @@ -51,6 +51,11 @@ unsigned GetCanvasHeightCF() return Canvas::getInstance()->height(); } +BBox GetBorderCF() +{ + return Canvas::getInstance()->border(); +} + void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels, float iSigma) { return Canvas::getInstance()->loadMap(iFileName, iMapName, iNbLevels, iSigma); diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.h b/source/blender/freestyle/intern/stroke/ContextFunctions.h index 5c0b88fd412..28ce918e919 100644 --- a/source/blender/freestyle/intern/stroke/ContextFunctions.h +++ b/source/blender/freestyle/intern/stroke/ContextFunctions.h @@ -54,10 +54,15 @@ LIB_STROKE_EXPORT unsigned GetCanvasWidthCF(); // GetCanvasHeight -/*! Returns the canvas width */ +/*! Returns the canvas height */ LIB_STROKE_EXPORT unsigned GetCanvasHeightCF(); +// GetBorder +/*! Returns the border */ +LIB_STROKE_EXPORT +BBox GetBorderCF(); + // Load map /*! Loads an image map for further reading */ LIB_STROKE_EXPORT diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index cb6ba0f85d0..cefb812f0cf 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1772,6 +1772,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mesh_automerge", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "automerge", 0); RNA_def_property_ui_text(prop, "AutoMerge Editing", "Automatically merge vertices moved to the same location"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */ prop = RNA_def_property(srna, "use_snap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP); diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index ee5f6109ab8..b8907e797ef 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -66,7 +66,7 @@ typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *) /* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */ /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */ -static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], +static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic, ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix) { Py_ssize_t i; @@ -110,7 +110,9 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[] error_prefix, dim + 1, dimsize[dim + 1], item_seq_size); ok = 0; } - else if (validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) { + else if (validate_array_type(item, dim + 1, totdim, dimsize, is_dynamic, + check_item_type, item_type_str, error_prefix) == -1) + { ok = 0; } @@ -129,7 +131,7 @@ static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[] error_prefix, dim + 1, Py_TYPE(seq)->tp_name); return -1; } - else if (seq_size != dimsize[dim]) { + else if ((seq_size != dimsize[dim]) && (is_dynamic == false)) { PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items, not %d", error_prefix, dim, dimsize[dim], seq_size); return -1; @@ -315,8 +317,12 @@ static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, { - if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) + const int prop_flag = RNA_property_flag(prop); + if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, (prop_flag & PROP_DYNAMIC) != 0, + check_item_type, item_type_str, error_prefix) == -1) + { return -1; + } return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix); } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 29555756f9f..6e70b4bcfc9 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4149,10 +4149,15 @@ static void set_renderlayer_lightgroups(Render *re, Scene *sce) void init_render_world(Render *re) { + void *wrld_prev[2] = { + re->wrld.aotables, + re->wrld.aosphere, + }; + int a; if (re->scene && re->scene->world) { - re->wrld= *(re->scene->world); + re->wrld = *(re->scene->world); copy_v3_v3(re->grvec, re->viewmat[2]); normalize_v3(re->grvec); @@ -4181,6 +4186,10 @@ void init_render_world(Render *re) re->wrld.linfac= 1.0f + powf((2.0f*re->wrld.exp + 0.5f), -10); re->wrld.logfac= logf((re->wrld.linfac-1.0f)/re->wrld.linfac) / re->wrld.range; + + /* restore runtime vars, needed for viewport rendering [#36005] */ + re->wrld.aotables = wrld_prev[0]; + re->wrld.aosphere = wrld_prev[1]; } @@ -4894,13 +4903,13 @@ void RE_Database_Free(Render *re) if (re->wrld.aosphere) { MEM_freeN(re->wrld.aosphere); re->wrld.aosphere= NULL; - if (re->scene) + if (re->scene && re->scene->world) re->scene->world->aosphere= NULL; } if (re->wrld.aotables) { MEM_freeN(re->wrld.aotables); re->wrld.aotables= NULL; - if (re->scene) + if (re->scene && re->scene->world) re->scene->world->aotables= NULL; } if (re->r.mode & R_RAYTRACE) @@ -5247,6 +5256,9 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l re->main= bmain; re->scene= scene; re->lay= lay; + + if (re->r.scemode & R_VIEWPORT_PREVIEW) + re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); /* scene needs to be set to get camera */ camera= RE_GetCamera(re); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index f7d347e8a5a..dfdfe973241 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1676,6 +1676,9 @@ static void add_freestyle(Render *re, int render) } FRS_finish_stroke_rendering(re); + + /* restore the global R value (invalidated by nested execution of the internal renderer) */ + R = *re; } /* merges the results of Freestyle stroke rendering into a given render result */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 5225a6dfa37..afd380a77f7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -252,7 +252,7 @@ void WM_operator_properties_border(struct wmOperatorType *ot); void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect); void WM_operator_properties_gesture_border(struct wmOperatorType *ot, bool extend); void WM_operator_properties_mouse_select(struct wmOperatorType *ot); -void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, bool cursor); +void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor); void WM_operator_properties_select_all(struct wmOperatorType *ot); void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9e0cb6a1d38..b9a9d6b1957 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1175,7 +1175,7 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot) RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection"); } -void WM_operator_properties_gesture_straightline(wmOperatorType *ot, bool cursor) +void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) { RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX); RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX); @@ -1880,6 +1880,7 @@ static void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot) { ot->name = "Add Autoexec Path"; ot->idname = "WM_OT_userpref_autoexec_path_add"; + ot->description = "Add path to exclude from autoexecution"; ot->exec = wm_userpref_autoexec_add_exec; ot->poll = WM_operator_winactive; @@ -1901,6 +1902,7 @@ static void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot) { ot->name = "Remove Autoexec Path"; ot->idname = "WM_OT_userpref_autoexec_path_remove"; + ot->description = "Remove path to exclude from autoexecution"; ot->exec = wm_userpref_autoexec_remove_exec; ot->poll = WM_operator_winactive; diff --git a/source/creator/creator.c b/source/creator/creator.c index bbc9d818b56..32502e2bcb0 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -1586,10 +1586,6 @@ int main(int argc, const char **argv) /* this is properly initialized with user defs, but this is default */ /* call after loading the startup.blend so we can read U.tempdir */ BLI_init_temporary_dir(U.tempdir); - -#ifdef WITH_SDL - BLI_setenv("SDL_VIDEODRIVER", "dummy"); -#endif } else { #ifndef WITH_PYTHON_MODULE