diff options
Diffstat (limited to 'release')
55 files changed, 372 insertions, 1204 deletions
diff --git a/release/datafiles/icons/brush.gpencil_draw.tint.dat b/release/datafiles/icons/brush.gpencil_draw.tint.dat Binary files differindex 016e4304498..32d8a5f04e4 100644 --- a/release/datafiles/icons/brush.gpencil_draw.tint.dat +++ b/release/datafiles/icons/brush.gpencil_draw.tint.dat diff --git a/release/datafiles/icons/brush.paint_texture.draw.dat b/release/datafiles/icons/brush.paint_texture.draw.dat Binary files differindex cfa5f1a6042..678a9ea26e5 100644 --- a/release/datafiles/icons/brush.paint_texture.draw.dat +++ b/release/datafiles/icons/brush.paint_texture.draw.dat diff --git a/release/datafiles/icons/brush.paint_texture.soften.dat b/release/datafiles/icons/brush.paint_texture.soften.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_texture.soften.dat +++ b/release/datafiles/icons/brush.paint_texture.soften.dat diff --git a/release/datafiles/icons/brush.paint_vertex.blur.dat b/release/datafiles/icons/brush.paint_vertex.blur.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_vertex.blur.dat +++ b/release/datafiles/icons/brush.paint_vertex.blur.dat diff --git a/release/datafiles/icons/brush.paint_vertex.draw.dat b/release/datafiles/icons/brush.paint_vertex.draw.dat Binary files differindex c1a8796ea02..74e00d243d6 100644 --- a/release/datafiles/icons/brush.paint_vertex.draw.dat +++ b/release/datafiles/icons/brush.paint_vertex.draw.dat diff --git a/release/datafiles/icons/brush.paint_vertex.replace.dat b/release/datafiles/icons/brush.paint_vertex.replace.dat Binary files differindex a37fdf2e1b1..676436548a7 100644 --- a/release/datafiles/icons/brush.paint_vertex.replace.dat +++ b/release/datafiles/icons/brush.paint_vertex.replace.dat diff --git a/release/datafiles/icons/brush.paint_weight.blur.dat b/release/datafiles/icons/brush.paint_weight.blur.dat Binary files differindex 8c547809792..2128de71dff 100644 --- a/release/datafiles/icons/brush.paint_weight.blur.dat +++ b/release/datafiles/icons/brush.paint_weight.blur.dat diff --git a/release/datafiles/icons/brush.paint_weight.draw.dat b/release/datafiles/icons/brush.paint_weight.draw.dat Binary files differindex cdb4ccf5efb..a2641927371 100644 --- a/release/datafiles/icons/brush.paint_weight.draw.dat +++ b/release/datafiles/icons/brush.paint_weight.draw.dat diff --git a/release/datafiles/icons/brush.particle.add.dat b/release/datafiles/icons/brush.particle.add.dat Binary files differindex 3c4f65cf6e2..b66f4da5b71 100644 --- a/release/datafiles/icons/brush.particle.add.dat +++ b/release/datafiles/icons/brush.particle.add.dat diff --git a/release/datafiles/icons/brush.particle.comb.dat b/release/datafiles/icons/brush.particle.comb.dat Binary files differindex 8b656db622b..d6dd75a35d7 100644 --- a/release/datafiles/icons/brush.particle.comb.dat +++ b/release/datafiles/icons/brush.particle.comb.dat diff --git a/release/datafiles/icons/brush.particle.cut.dat b/release/datafiles/icons/brush.particle.cut.dat Binary files differindex 97dc3e6099b..e7ef86e2fbc 100644 --- a/release/datafiles/icons/brush.particle.cut.dat +++ b/release/datafiles/icons/brush.particle.cut.dat diff --git a/release/datafiles/icons/brush.particle.length.dat b/release/datafiles/icons/brush.particle.length.dat Binary files differindex 59e74fd9912..e3aa3f2f9df 100644 --- a/release/datafiles/icons/brush.particle.length.dat +++ b/release/datafiles/icons/brush.particle.length.dat diff --git a/release/datafiles/icons/brush.particle.puff.dat b/release/datafiles/icons/brush.particle.puff.dat Binary files differindex 9dd194bfd93..db2bab46bfe 100644 --- a/release/datafiles/icons/brush.particle.puff.dat +++ b/release/datafiles/icons/brush.particle.puff.dat diff --git a/release/datafiles/icons/brush.particle.smooth.dat b/release/datafiles/icons/brush.particle.smooth.dat Binary files differindex 54b80a25841..7deaa4ed082 100644 --- a/release/datafiles/icons/brush.particle.smooth.dat +++ b/release/datafiles/icons/brush.particle.smooth.dat diff --git a/release/datafiles/icons/brush.sculpt.cloth.dat b/release/datafiles/icons/brush.sculpt.cloth.dat Binary files differindex 5e8fad60035..7e936167381 100644 --- a/release/datafiles/icons/brush.sculpt.cloth.dat +++ b/release/datafiles/icons/brush.sculpt.cloth.dat diff --git a/release/datafiles/icons/brush.sculpt.draw.dat b/release/datafiles/icons/brush.sculpt.draw.dat Binary files differindex 36ec5575bdd..014ce10e8cc 100644 --- a/release/datafiles/icons/brush.sculpt.draw.dat +++ b/release/datafiles/icons/brush.sculpt.draw.dat diff --git a/release/datafiles/icons/brush.sculpt.draw_sharp.dat b/release/datafiles/icons/brush.sculpt.draw_sharp.dat Binary files differindex ad42f4bf870..9bea1b02894 100644 --- a/release/datafiles/icons/brush.sculpt.draw_sharp.dat +++ b/release/datafiles/icons/brush.sculpt.draw_sharp.dat diff --git a/release/datafiles/icons/brush.sculpt.elastic_deform.dat b/release/datafiles/icons/brush.sculpt.elastic_deform.dat Binary files differindex 6d0ea25c1fe..0b12d717d3a 100644 --- a/release/datafiles/icons/brush.sculpt.elastic_deform.dat +++ b/release/datafiles/icons/brush.sculpt.elastic_deform.dat diff --git a/release/datafiles/icons/brush.sculpt.layer.dat b/release/datafiles/icons/brush.sculpt.layer.dat Binary files differindex 184f1bc9c13..1031d95332a 100644 --- a/release/datafiles/icons/brush.sculpt.layer.dat +++ b/release/datafiles/icons/brush.sculpt.layer.dat diff --git a/release/datafiles/icons/brush.sculpt.nudge.dat b/release/datafiles/icons/brush.sculpt.nudge.dat Binary files differindex 309a01a5645..e10157e9cd0 100644 --- a/release/datafiles/icons/brush.sculpt.nudge.dat +++ b/release/datafiles/icons/brush.sculpt.nudge.dat diff --git a/release/datafiles/icons/brush.sculpt.rotate.dat b/release/datafiles/icons/brush.sculpt.rotate.dat Binary files differindex a0bb63d14db..8d1723a8c71 100644 --- a/release/datafiles/icons/brush.sculpt.rotate.dat +++ b/release/datafiles/icons/brush.sculpt.rotate.dat diff --git a/release/datafiles/icons/brush.sculpt.snake_hook.dat b/release/datafiles/icons/brush.sculpt.snake_hook.dat Binary files differindex 64256d93702..20300c1d97c 100644 --- a/release/datafiles/icons/brush.sculpt.snake_hook.dat +++ b/release/datafiles/icons/brush.sculpt.snake_hook.dat diff --git a/release/datafiles/icons/brush.sculpt.thumb.dat b/release/datafiles/icons/brush.sculpt.thumb.dat Binary files differindex a2634afced9..9da33eccd98 100644 --- a/release/datafiles/icons/brush.sculpt.thumb.dat +++ b/release/datafiles/icons/brush.sculpt.thumb.dat diff --git a/release/datafiles/icons/ops.curve.draw.dat b/release/datafiles/icons/ops.curve.draw.dat Binary files differindex 8ae8ef5b1c8..cf2c8e31bcb 100644 --- a/release/datafiles/icons/ops.curve.draw.dat +++ b/release/datafiles/icons/ops.curve.draw.dat diff --git a/release/datafiles/icons/ops.gpencil.draw.dat b/release/datafiles/icons/ops.gpencil.draw.dat Binary files differindex d05e67d276c..e71644f4968 100644 --- a/release/datafiles/icons/ops.gpencil.draw.dat +++ b/release/datafiles/icons/ops.gpencil.draw.dat diff --git a/release/datafiles/icons/ops.gpencil.draw.eraser.dat b/release/datafiles/icons/ops.gpencil.draw.eraser.dat Binary files differindex 2dc1653f810..44f65c4581d 100644 --- a/release/datafiles/icons/ops.gpencil.draw.eraser.dat +++ b/release/datafiles/icons/ops.gpencil.draw.eraser.dat diff --git a/release/datafiles/icons/ops.gpencil.draw.line.dat b/release/datafiles/icons/ops.gpencil.draw.line.dat Binary files differindex 53fa0193fa9..bbfaf28bc5e 100644 --- a/release/datafiles/icons/ops.gpencil.draw.line.dat +++ b/release/datafiles/icons/ops.gpencil.draw.line.dat diff --git a/release/datafiles/icons/ops.gpencil.draw.poly.dat b/release/datafiles/icons/ops.gpencil.draw.poly.dat Binary files differindex a223c9eb90c..e3ca2f35ece 100644 --- a/release/datafiles/icons/ops.gpencil.draw.poly.dat +++ b/release/datafiles/icons/ops.gpencil.draw.poly.dat diff --git a/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat b/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat Binary files differindex 90ba16d846a..d480913608d 100644 --- a/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat +++ b/release/datafiles/icons/ops.gpencil.sculpt_smooth.dat diff --git a/release/datafiles/icons/ops.gpencil.sculpt_strength.dat b/release/datafiles/icons/ops.gpencil.sculpt_strength.dat Binary files differindex d3f48931831..7fced673192 100644 --- a/release/datafiles/icons/ops.gpencil.sculpt_strength.dat +++ b/release/datafiles/icons/ops.gpencil.sculpt_strength.dat diff --git a/release/datafiles/icons/ops.gpencil.sculpt_weight.dat b/release/datafiles/icons/ops.gpencil.sculpt_weight.dat Binary files differindex d5441fcbeb9..01c9587ec2e 100644 --- a/release/datafiles/icons/ops.gpencil.sculpt_weight.dat +++ b/release/datafiles/icons/ops.gpencil.sculpt_weight.dat diff --git a/release/datafiles/icons/ops.paint.weight_sample.dat b/release/datafiles/icons/ops.paint.weight_sample.dat Binary files differindex 423365f5a55..a428ae67e4c 100644 --- a/release/datafiles/icons/ops.paint.weight_sample.dat +++ b/release/datafiles/icons/ops.paint.weight_sample.dat diff --git a/release/datafiles/icons/ops.paint.weight_sample_group.dat b/release/datafiles/icons/ops.paint.weight_sample_group.dat Binary files differindex b37eb59ad23..863496f8908 100644 --- a/release/datafiles/icons/ops.paint.weight_sample_group.dat +++ b/release/datafiles/icons/ops.paint.weight_sample_group.dat diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 2b3c19f5f61fc72dba56a7edfdc4e55e2327dc1 +Subproject 4af22e0492f401c609a0203cad1a9bc7fa00b86 diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index fbdb226ab6d..df1be29f642 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -109,7 +109,7 @@ const UserDef U_default = { .keyconfigstr = "blender", .undosteps = 32, .undomemory = 0, - .gp_manhattendist = 1, + .gp_manhattandist = 1, .gp_euclideandist = 2, .gp_eraser = 25, .gp_settings = 0, diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 49c39f59fbc464dd34388990123f271c39eacbf +Subproject 25b00a0a52c81408b9dc15ea320a79ee956b3c0 diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject a52733b58d95ce60ecde95a9eca242e7319c285 +Subproject f2f4a8b3bfa36ee49f7bdb3a1acb40ef4b39ee3 diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index dde718a45b4..132a711e845 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -3370,16 +3370,14 @@ def km_grease_pencil_stroke_paint_fill(params): # Fill ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("on_back", False)]}), - ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("on_back", True)]}), + ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("on_back", False)]}), # If press alternate key, the brush now it's for drawing areas - ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, - {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True)]}), + ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_stabilizer", True)]}), # If press alternative key, the brush now it's for drawing lines ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_fill", True)]}), - # Lasso select - ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), + {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_stabilizer", True), ("disable_fill", True)]}), ]) return keymap @@ -6293,10 +6291,10 @@ def km_3d_view_tool_sculpt_box_mask(params): "3D View Tool: Sculpt, Box Mask", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("view3d.select_box", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("mode", 'ADD')]}), - ("view3d.select_box", {"type": params.tool_tweak, "value": 'ANY', "ctrl": True}, - {"properties": [("mode", 'SUB')]}), + ("paint.mask_box_gesture", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("value", 1.0)]}), + ("paint.mask_box_gesture", {"type": params.tool_tweak, "value": 'ANY', "ctrl": True}, + {"properties": [("value", 0.0)]}), ]}, ) @@ -6355,6 +6353,18 @@ def km_3d_view_tool_sculpt_mask_by_color(params): ]}, ) +def km_3d_view_tool_sculpt_face_set_edit(params): + return ( + "3D View Tool: Sculpt, Face Set Edit", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + ("sculpt.face_set_edit", {"type": params.tool_mouse, "value": 'ANY'}, + None), + ("sculpt.face_set_edit", {"type": params.tool_tweak, "value": 'ANY'}, + None) + ]}, + ) + def km_3d_view_tool_paint_weight_sample_weight(params): return ( "3D View Tool: Paint Weight, Sample Weight", @@ -6390,12 +6400,12 @@ def km_3d_view_tool_paint_gpencil_line(params): "3D View Tool: Paint Gpencil, Line", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'LINE'), ("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_line", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6406,10 +6416,10 @@ def km_3d_view_tool_paint_gpencil_polyline(params): "3D View Tool: Paint Gpencil, Polyline", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'POLYLINE'), ("wait_for_input", False)]}), + ("gpencil.primitive_polyline", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_polyline", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6420,12 +6430,12 @@ def km_3d_view_tool_paint_gpencil_box(params): "3D View Tool: Paint Gpencil, Box", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'BOX'), ("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_box", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6437,12 +6447,12 @@ def km_3d_view_tool_paint_gpencil_circle(params): "3D View Tool: Paint Gpencil, Circle", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, - {"properties": [("type", 'CIRCLE'), ("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": params.tool_tweak, "value": 'ANY'}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("wait_for_input", False)]}), + ("gpencil.primitive_circle", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6454,12 +6464,12 @@ def km_3d_view_tool_paint_gpencil_arc(params): "3D View Tool: Paint Gpencil, Arc", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, - {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + ("gpencil.primitive_curve", {"type": params.tool_tweak, "value": 'ANY'}, {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), - ("gpencil.primitive", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + ("gpencil.primitive_curve", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, {"properties": [("type", 'ARC'), ("wait_for_input", False)]}), + ("gpencil.primitive_curve", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("type",'ARC'), ("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), ]}, @@ -6471,7 +6481,7 @@ def km_3d_view_tool_paint_gpencil_curve(params): "3D View Tool: Paint Gpencil, Curve", {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, {"items": [ - ("gpencil.primitive", {"type": params.tool_tweak, "value": 'ANY'}, + ("gpencil.primitive_curve", {"type": params.tool_tweak, "value": 'ANY'}, {"properties": [("type", 'CURVE'), ("wait_for_input", False)]}), # Lasso select ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), @@ -6898,6 +6908,7 @@ def generate_keymaps(params=None): km_3d_view_tool_sculpt_cloth_filter(params), km_3d_view_tool_sculpt_color_filter(params), km_3d_view_tool_sculpt_mask_by_color(params), + km_3d_view_tool_sculpt_face_set_edit(params), km_3d_view_tool_paint_weight_sample_weight(params), km_3d_view_tool_paint_weight_sample_vertex_group(params), km_3d_view_tool_paint_weight_gradient(params), diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py index eedf07935c8..c72a7521557 100644 --- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py +++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py @@ -2465,16 +2465,14 @@ def km_grease_pencil_stroke_paint_fill(params): # Fill ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("on_back", False)]}), - ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, - {"properties": [("on_back", True)]}), + ("gpencil.fill", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, + {"properties": [("on_back", False)]}), # If press alternate key, the brush now it's for drawing areas - ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, - {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True)]}), + ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, + {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_stabilizer", True)]}), # If press alternative key, the brush now it's for drawing lines - ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True, "shift": True}, - {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_fill", True)]}), - # Lasso select - ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None), + ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True}, + {"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_stabilizer", True), ("disable_fill", True)]}), ]) return keymap diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py index c39a7afcff9..c927cc184a3 100644 --- a/release/scripts/startup/bl_operators/__init__.py +++ b/release/scripts/startup/bl_operators/__init__.py @@ -46,7 +46,6 @@ _modules = [ "userpref", "uvcalc_follow_active", "uvcalc_lightmap", - "uvcalc_smart_project", "vertexpaint_dirt", "view3d", "gpencil_mesh_bake", diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 311631ac65f..d0344b88be8 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -561,9 +561,61 @@ class QuickLiquid(Operator): return {'FINISHED'} +class QuickParticles(Operator): + """Use active object as particle emitter""" + bl_idname = "object.quick_particles" + bl_label = "Quick Particles" + + @classmethod + def poll(cls, context): + if not context.preferences.experimental.use_new_particle_system: + return False + if context.mode != 'OBJECT': + return False + if context.active_object is None: + return False + if context.active_object.type != 'MESH': + return False + return True + + def execute(self, context): + pointcloud = bpy.data.pointclouds.new("Particles") + pointcloud_object = bpy.data.objects.new("Particles", pointcloud) + modifier = pointcloud_object.modifiers.new("Simulation", 'SIMULATION') + simulation = bpy.data.simulations.new("Particle Simulation") + tree = simulation.node_tree + + default_name = "Particles" + particle_simulation_node = tree.nodes.new('SimulationNodeParticleSimulation') + particle_simulation_node.name = default_name + emitter_node = tree.nodes.new('SimulationNodeParticleMeshEmitter') + emitter_node.location.x -= 200 + emitter_node.location.y += 50 + emitter_node.inputs["Object"].default_value = context.active_object + force_node = tree.nodes.new('SimulationNodeForce') + force_node.location.x -= 200 + force_node.location.y -= 100 + force_node.inputs["Force"].default_value = (0, 0, -1) + + tree.links.new(particle_simulation_node.inputs["Emitters"], emitter_node.outputs["Emitter"]) + tree.links.new(particle_simulation_node.inputs["Forces"], force_node.outputs["Force"]) + + modifier.simulation = simulation + modifier.data_path = default_name + + for obj in context.selected_objects: + obj.select_set(False) + + context.collection.objects.link(pointcloud_object) + pointcloud_object.select_set(True) + context.view_layer.objects.active = pointcloud_object + pointcloud_object.show_bounds = True + return {'FINISHED'} + classes = ( QuickExplode, QuickFur, QuickSmoke, QuickLiquid, + QuickParticles, ) diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index 1ac64f85cad..ceef2df63ff 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -119,8 +119,11 @@ class PREFERENCES_OT_copy_prev(Operator): # Find config folder from previous version. import os version = bpy.app.version + version_new = ((version[0] * 100) + version[1]) version_old = ((version[0] * 100) + version[1]) - 1 - while version_old % 10 > 0: + # Ensure we only try to copy files from a point release. + # The check below ensures the second numbers match. + while (version_new % 100) // 10 == (version_old % 100) // 10: version_split = version_old // 100, version_old % 100 if os.path.isdir(cls._old_version_path(version_split)): return version_split diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index 2befb7c73e2..7af5cd5ee5f 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -613,7 +613,7 @@ class LightMapPack(Operator): # Image & UVs... PREF_PACK_IN_ONE: BoolProperty( - name="Share Tex Space", + name="Share Texture Space", description=( "Objects Share texture space, map all objects " "into 1 uvmap" diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py deleted file mode 100644 index 1f56cbe6d57..00000000000 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ /dev/null @@ -1,1053 +0,0 @@ -# ##### 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. -# -# ##### END GPL LICENSE BLOCK ##### - -# TODO <pep8 compliant> - -from mathutils import ( - Matrix, - Vector, - geometry, -) -import bpy -from bpy.types import Operator - -DEG_TO_RAD = 0.017453292519943295 # pi/180.0 -# see bugs: -# - T31598 (when too small). -# - T48086 (when too big). -SMALL_NUM = 1e-12 - - -global USER_FILL_HOLES -global USER_FILL_HOLES_QUALITY -USER_FILL_HOLES = None -USER_FILL_HOLES_QUALITY = None - - -def pointInTri2D(v, v1, v2, v3): - key = v1.x, v1.y, v2.x, v2.y, v3.x, v3.y - - # Commented because its slower to do the bounds check, we should really cache the bounds info for each face. - ''' - # BOUNDS CHECK - xmin= 1000000 - ymin= 1000000 - - xmax= -1000000 - ymax= -1000000 - - for i in (0,2,4): - x= key[i] - y= key[i+1] - - if xmax<x: xmax= x - if ymax<y: ymax= y - if xmin>x: xmin= x - if ymin>y: ymin= y - - x= v.x - y= v.y - - if x<xmin or x>xmax or y < ymin or y > ymax: - return False - # Done with bounds check - ''' - try: - mtx = dict_matrix[key] - if not mtx: - return False - except: - side1 = v2 - v1 - side2 = v3 - v1 - - nor = side1.cross(side2) - - mtx = Matrix((side1, side2, nor)) - - # Zero area 2d tri, even tho we throw away zero area faces - # the projection UV can result in a zero area UV. - if not mtx.determinant(): - dict_matrix[key] = None - return False - - mtx.invert() - - dict_matrix[key] = mtx - - uvw = (v - v1) @ mtx - return 0 <= uvw[0] and 0 <= uvw[1] and uvw[0] + uvw[1] <= 1 - - -def boundsIsland(faces): - minx = maxx = faces[0].uv[0][0] # Set initial bounds. - miny = maxy = faces[0].uv[0][1] - # print len(faces), minx, maxx, miny , maxy - for f in faces: - for uv in f.uv: - x = uv.x - y = uv.y - if x < minx: - minx = x - if y < miny: - miny = y - if x > maxx: - maxx = x - if y > maxy: - maxy = y - - return minx, miny, maxx, maxy - - -""" -def boundsEdgeLoop(edges): - minx = maxx = edges[0][0] # Set initial bounds. - miny = maxy = edges[0][1] - # print len(faces), minx, maxx, miny , maxy - for ed in edges: - for pt in ed: - x= pt[0] - y= pt[1] - if x<minx: x= minx - if y<miny: y= miny - if x>maxx: x= maxx - if y>maxy: y= maxy - - return minx, miny, maxx, maxy -""" - -# Turns the islands into a list of unpordered edges (Non internal) -# Only for UV's -# only returns outline edges for intersection tests. and unique points. - - -def island2Edge(island): - - # Vert index edges - edges = {} - - unique_points = {} - - for f in island: - f_uvkey = list(map(tuple, f.uv)) - - for vIdx in range(len(f_uvkey)): - unique_points[f_uvkey[vIdx]] = f.uv[vIdx] - - if f.v[vIdx].index > f.v[vIdx - 1].index: - i1 = vIdx - 1 - i2 = vIdx - else: - i1 = vIdx - i2 = vIdx - 1 - - try: - edges[f_uvkey[i1], f_uvkey[i2]] *= 0 # sets any edge with more than 1 user to 0 are not returned. - except: - edges[f_uvkey[i1], f_uvkey[i2]] = (f.uv[i1] - f.uv[i2]).length - - # If 2 are the same then they will be together, but full [a,b] order is not correct. - - # Sort by length - length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.items() if value != 0] - - length_sorted_edges.sort(key=lambda a: -a[2]) # largest first - - # Its okay to leave the length in there. - # for e in length_sorted_edges: - # e.pop(2) - - # return edges and unique points - return length_sorted_edges, [v.to_3d() for v in unique_points.values()] - - -def pointInIsland(pt, island): - vec1, vec2, vec3 = Vector(), Vector(), Vector() - for f in island: - vec1.x, vec1.y = f.uv[0] - vec2.x, vec2.y = f.uv[1] - vec3.x, vec3.y = f.uv[2] - - if pointInTri2D(pt, vec1, vec2, vec3): - return True - - if len(f.v) == 4: - vec1.x, vec1.y = f.uv[0] - vec2.x, vec2.y = f.uv[2] - vec3.x, vec3.y = f.uv[3] - if pointInTri2D(pt, vec1, vec2, vec3): - return True - return False - - -# box is (left,bottom, right, top) -def islandIntersectUvIsland(source, target, SourceOffset): - # Is 1 point in the box, inside the vertLoops - edgeLoopsSource = source[6] # Pretend this is offset - edgeLoopsTarget = target[6] - - # Edge intersect test - for ed in edgeLoopsSource: - for seg in edgeLoopsTarget: - i = geometry.intersect_line_line_2d(seg[0], - seg[1], - SourceOffset + ed[0], - SourceOffset + ed[1], - ) - if i: - return 1 # LINE INTERSECTION - - # 1 test for source being totally inside target - SourceOffset.resize_3d() - for pv in source[7]: - if pointInIsland(pv + SourceOffset, target[0]): - return 2 # SOURCE INSIDE TARGET - - # 2 test for a part of the target being totally inside the source. - for pv in target[7]: - if pointInIsland(pv - SourceOffset, source[0]): - return 3 # PART OF TARGET INSIDE SOURCE. - - return 0 # NO INTERSECTION - - -def rotate_uvs(uv_points, angle): - - if angle != 0.0: - mat = Matrix.Rotation(angle, 2) - for uv in uv_points: - uv[:] = mat @ uv - - -def optiRotateUvIsland(faces): - uv_points = [uv for f in faces for uv in f.uv] - angle = geometry.box_fit_2d(uv_points) - - if angle != 0.0: - rotate_uvs(uv_points, angle) - - # orient them vertically (could be an option) - minx, miny, maxx, maxy = boundsIsland(faces) - w, h = maxx - minx, maxy - miny - # use epsilon so we don't randomly rotate (almost) perfect squares. - if h + 0.00001 < w: - from math import pi - angle = pi / 2.0 - rotate_uvs(uv_points, angle) - - -# Takes an island list and tries to find concave, hollow areas to pack smaller islands into. -def mergeUvIslands(islandList): - global USER_FILL_HOLES - global USER_FILL_HOLES_QUALITY - - # Pack islands to bottom LHS - # Sync with island - - # islandTotFaceArea = [] # A list of floats, each island area - # islandArea = [] # a list of tuples ( area, w,h) - - decoratedIslandList = [] - - islandIdx = len(islandList) - while islandIdx: - islandIdx -= 1 - minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) - w, h = maxx - minx, maxy - miny - - totFaceArea = 0 - offset = Vector((minx, miny)) - for f in islandList[islandIdx]: - for uv in f.uv: - uv -= offset - - totFaceArea += f.area - - islandBoundsArea = w * h - efficiency = abs(islandBoundsArea - totFaceArea) - - # UV Edge list used for intersections as well as unique points. - edges, uniqueEdgePoints = island2Edge(islandList[islandIdx]) - - decoratedIslandList.append([ - islandList[islandIdx], - totFaceArea, - efficiency, - islandBoundsArea, - w, - h, - edges, - uniqueEdgePoints, - ]) - - # Sort by island bounding box area, smallest face area first. - # no.. chance that to most simple edge loop first. - decoratedIslandListAreaSort = decoratedIslandList[:] - - decoratedIslandListAreaSort.sort(key=lambda A: A[3]) - - # sort by efficiency, Least Efficient first. - decoratedIslandListEfficSort = decoratedIslandList[:] - # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) - - decoratedIslandListEfficSort.sort(key=lambda A: -A[2]) - - # ================================================== THESE CAN BE TWEAKED. - # This is a quality value for the number of tests. - # from 1 to 4, generic quality value is from 1 to 100 - USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1 - - # If 100 will test as long as there is enough free space. - # this is rarely enough, and testing takes a while, so lower quality speeds this up. - - # 1 means they have the same quality - USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (((100 - USER_FILL_HOLES_QUALITY) / 100.0) * 5) - - # print 'USER_STEP_QUALITY', USER_STEP_QUALITY - # print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY - - removedCount = 0 - - areaIslandIdx = 0 - ctrl = Window.Qual.CTRL - BREAK = False - while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: - sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] - # Already packed? - if not sourceIsland[0]: - areaIslandIdx += 1 - else: - efficIslandIdx = 0 - while efficIslandIdx < len(decoratedIslandListEfficSort) and not BREAK: - - if Window.GetKeyQualifiers() & ctrl: - BREAK = True - break - - # Now we have 2 islands, if the efficiency of the islands lowers there's an - # increasing likely hood that we can fit merge into the bigger UV island. - # this ensures a tight fit. - - # Just use figures we have about user/unused area to see if they might fit. - - targetIsland = decoratedIslandListEfficSort[efficIslandIdx] - - if sourceIsland[0] == targetIsland[0] or\ - not targetIsland[0] or\ - not sourceIsland[0]: - pass - else: - - #~ ([island, totFaceArea, efficiency, islandArea, w,h]) - # Wasted space on target is greater then UV bounding island area. - - #~ if targetIsland[3] > (sourceIsland[2]) and\ # - # ~ print USER_FREE_SPACE_TO_TEST_QUALITY - if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ - targetIsland[4] > sourceIsland[4] and\ - targetIsland[5] > sourceIsland[5]: - - # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1]) - - # These enough spare space lets move the box until it fits - - # How many times does the source fit into the target x/y - blockTestXUnit = targetIsland[4] / sourceIsland[4] - blockTestYUnit = targetIsland[5] / sourceIsland[5] - - boxLeft = 0 - - # Distance we can move between whilst staying inside the targets bounds. - testWidth = targetIsland[4] - sourceIsland[4] - testHeight = targetIsland[5] - sourceIsland[5] - - # Increment we move each test. x/y - xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY / 50) + 0.1))) - yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY / 50) + 0.1))) - - # Make sure were not moving less then a 3rg of our width/height - if xIncrement < sourceIsland[4] / 3: - xIncrement = sourceIsland[4] - if yIncrement < sourceIsland[5] / 3: - yIncrement = sourceIsland[5] - - boxLeft = 0 # Start 1 back so we can jump into the loop. - boxBottom = 0 # -yIncrement - - # ~ testcount= 0 - - while boxBottom <= testHeight: - # Should we use this? - not needed for now. - # ~ if Window.GetKeyQualifiers() & ctrl: - # ~ BREAK= True - # ~ break - - # testcount+=1 - # print 'Testing intersect' - Intersect = islandIntersectUvIsland( - sourceIsland, targetIsland, Vector((boxLeft, boxBottom))) - # print 'Done', Intersect - if Intersect == 1: # Line intersect, don't bother with this any more - pass - - if Intersect == 2: # Source inside target - """ - We have an intersection, if we are inside the target - then move us 1 whole width across, - Its possible this is a bad idea since 2 skinny Angular faces - could join without 1 whole move, but its a lot more optimal to speed this up - since we have already tested for it. - - It gives about 10% speedup with minimal errors. - """ - # Move the test along its width + SMALL_NUM - #boxLeft += sourceIsland[4] + SMALL_NUM - boxLeft += sourceIsland[4] - elif Intersect == 0: # No intersection?? Place it. - # Progress - removedCount += 1 -# XXX Window.DrawProgressBar(0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount) - - # Move faces into new island and offset - targetIsland[0].extend(sourceIsland[0]) - offset = Vector((boxLeft, boxBottom)) - - for f in sourceIsland[0]: - for uv in f.uv: - uv += offset - - del sourceIsland[0][:] # Empty - - # Move edge loop into new and offset. - # targetIsland[6].extend(sourceIsland[6]) - # while sourceIsland[6]: - targetIsland[6].extend([( - (e[0] + offset, e[1] + offset, e[2]) - ) for e in sourceIsland[6]]) - - del sourceIsland[6][:] # Empty - - # Sort by edge length, reverse so biggest are first. - - try: - targetIsland[6].sort(key=lambda A: A[2]) - except: - targetIsland[6].sort(lambda B, A: cmp(A[2], B[2])) - - targetIsland[7].extend(sourceIsland[7]) - offset = Vector((boxLeft, boxBottom, 0.0)) - for p in sourceIsland[7]: - p += offset - - del sourceIsland[7][:] - - # Decrement the efficiency - targetIsland[1] += sourceIsland[1] # Increment totFaceArea - targetIsland[2] -= sourceIsland[1] # Decrement efficiency - # IF we ever used these again, should set to 0, eg - sourceIsland[2] = 0 # No area if anyone wants to know - - break - - # INCREMENT NEXT LOCATION - if boxLeft > testWidth: - boxBottom += yIncrement - boxLeft = 0.0 - else: - boxLeft += xIncrement - # print testcount - - efficIslandIdx += 1 - areaIslandIdx += 1 - - # Remove empty islands - i = len(islandList) - while i: - i -= 1 - if not islandList[i]: - del islandList[i] # Can increment islands removed here. - -# Takes groups of faces. assumes face groups are UV groups. - - -def getUvIslands(faceGroups, me): - - # Get seams so we don't cross over seams - edge_seams = {} # should be a set - for ed in me.edges: - if ed.use_seam: - edge_seams[ed.key] = None # dummy var- use sets! - # Done finding seams - - islandList = [] - -# XXX Window.DrawProgressBar(0.0, 'Splitting %d projection groups into UV islands:' % len(faceGroups)) - # print '\tSplitting %d projection groups into UV islands:' % len(faceGroups), - # Find grouped faces - - faceGroupIdx = len(faceGroups) - - while faceGroupIdx: - faceGroupIdx -= 1 - faces = faceGroups[faceGroupIdx] - - if not faces: - continue - - # Build edge dict - edge_users = {} - - for i, f in enumerate(faces): - for ed_key in f.edge_keys: - if ed_key in edge_seams: # DELIMIT SEAMS! ;) - edge_users[ed_key] = [] # so as not to raise an error - else: - try: - edge_users[ed_key].append(i) - except: - edge_users[ed_key] = [i] - - # Modes - # 0 - face not yet touched. - # 1 - added to island list, and need to search - # 2 - touched and searched - don't touch again. - face_modes = [0] * len(faces) # initialize zero - untested. - - face_modes[0] = 1 # start the search with face 1 - - newIsland = [] - - newIsland.append(faces[0]) - - ok = True - while ok: - - ok = True - while ok: - ok = False - for i in range(len(faces)): - if face_modes[i] == 1: # search - for ed_key in faces[i].edge_keys: - for ii in edge_users[ed_key]: - if i != ii and face_modes[ii] == 0: - face_modes[ii] = ok = 1 # mark as searched - newIsland.append(faces[ii]) - - # mark as searched, don't look again. - face_modes[i] = 2 - - islandList.append(newIsland) - - ok = False - for i in range(len(faces)): - if face_modes[i] == 0: - newIsland = [] - newIsland.append(faces[i]) - - face_modes[i] = ok = 1 - break - # if not ok will stop looping - -# XXX Window.DrawProgressBar(0.1, 'Optimizing Rotation for %i UV Islands' % len(islandList)) - - for island in islandList: - optiRotateUvIsland(island) - - return islandList - - -def packIslands(islandList): - if USER_FILL_HOLES: - # XXX Window.DrawProgressBar(0.1, 'Merging Islands (Ctrl: skip merge)...') - mergeUvIslands(islandList) # Modify in place - - # Now we have UV islands, we need to pack them. - - # Make a synchronized list with the islands - # so we can box pack the islands. - packBoxes = [] - - # Keep a list of X/Y offset so we can save time by writing the - # uv's and packed data in one pass. - islandOffsetList = [] - - islandIdx = 0 - - while islandIdx < len(islandList): - minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) - - w, h = maxx - minx, maxy - miny - - if USER_ISLAND_MARGIN: - minx -= USER_ISLAND_MARGIN * w / 2 - miny -= USER_ISLAND_MARGIN * h / 2 - maxx += USER_ISLAND_MARGIN * w / 2 - maxy += USER_ISLAND_MARGIN * h / 2 - - # recalc width and height - w, h = maxx - minx, maxy - miny - - if w < SMALL_NUM: - w = SMALL_NUM - if h < SMALL_NUM: - h = SMALL_NUM - - """Save the offset to be applied later, - we could apply to the UVs now and align them to the bottom left hand area - of the UV coords like the box packer imagines they are - but, its quicker just to remember their offset and - apply the packing and offset in 1 pass """ - islandOffsetList.append((minx, miny)) - - # Add to boxList. use the island idx for the BOX id. - packBoxes.append([0, 0, w, h]) - islandIdx += 1 - - # Now we have a list of boxes to pack that syncs - # with the islands. - - # print '\tPacking UV Islands...' -# XXX Window.DrawProgressBar(0.7, "Packing %i UV Islands..." % len(packBoxes) ) - - # time1 = time.time() - packWidth, packHeight = geometry.box_pack_2d(packBoxes) - - # print 'Box Packing Time:', time.time() - time1 - - # if len(packedLs) != len(islandList): - # raise ValueError("Packed boxes differs from original length") - - # print '\tWriting Packed Data to faces' -# XXX Window.DrawProgressBar(0.8, "Writing Packed Data to faces") - - # Sort by ID, so there in sync again - islandIdx = len(islandList) - # Having these here avoids divide by 0 - if islandIdx: - - if USER_STRETCH_ASPECT: - # Maximize to uv area?? Will write a normalize function. - xfactor = 1.0 / packWidth - yfactor = 1.0 / packHeight - else: - # Keep proportions. - xfactor = yfactor = 1.0 / max(packWidth, packHeight) - - while islandIdx: - islandIdx -= 1 - # Write the packed values to the UV's - - xoffset = packBoxes[islandIdx][0] - islandOffsetList[islandIdx][0] - yoffset = packBoxes[islandIdx][1] - islandOffsetList[islandIdx][1] - - for f in islandList[islandIdx]: # Offsetting the UV's so they fit in there packed box - for uv in f.uv: - uv.x = (uv.x + xoffset) * xfactor - uv.y = (uv.y + yoffset) * yfactor - - -def VectoQuat(vec): - vec = vec.normalized() - return vec.to_track_quat('Z', 'X' if abs(vec.x) > 0.5 else 'Y').inverted() - - -class thickface: - __slost__ = "v", "uv", "no", "area", "edge_keys" - - def __init__(self, face, uv_layer, mesh_verts): - self.v = [mesh_verts[i] for i in face.vertices] - self.uv = [uv_layer[i].uv for i in face.loop_indices] - - self.no = face.normal.copy() - self.area = face.area - self.edge_keys = face.edge_keys - - -def main_consts(): - from math import radians - - global ROTMAT_2D_POS_90D - global ROTMAT_2D_POS_45D - global RotMatStepRotation - - ROTMAT_2D_POS_90D = Matrix.Rotation(radians(90.0), 2) - ROTMAT_2D_POS_45D = Matrix.Rotation(radians(45.0), 2) - - RotMatStepRotation = [] - rot_angle = 22.5 # 45.0/2 - while rot_angle > 0.1: - RotMatStepRotation.append([ - Matrix.Rotation(radians(+rot_angle), 2), - Matrix.Rotation(radians(-rot_angle), 2), - ]) - - rot_angle = rot_angle / 2.0 - - -global ob -ob = None - - -def main(context, - island_margin, - projection_limit, - user_area_weight, - use_aspect, - stretch_to_bounds, - ): - global USER_FILL_HOLES - global USER_FILL_HOLES_QUALITY - global USER_STRETCH_ASPECT - global USER_ISLAND_MARGIN - - from math import cos - import time - - global dict_matrix - dict_matrix = {} - - # Constants: - # Takes a list of faces that make up a UV island and rotate - # until they optimally fit inside a square. - global ROTMAT_2D_POS_90D - global ROTMAT_2D_POS_45D - global RotMatStepRotation - main_consts() - - # Create the variables. - USER_PROJECTION_LIMIT = projection_limit - USER_ONLY_SELECTED_FACES = True - USER_SHARE_SPACE = 1 # Only for hole filling. - USER_STRETCH_ASPECT = stretch_to_bounds - USER_ISLAND_MARGIN = island_margin # Only for hole filling. - USER_FILL_HOLES = 0 - USER_FILL_HOLES_QUALITY = 50 # Only for hole filling. - USER_VIEW_INIT = 0 # Only for hole filling. - - is_editmode = (context.mode == 'EDIT_MESH') - if is_editmode: - obList = context.objects_in_mode_unique_data - else: - obList = [ - ob for ob in context.selected_editable_objects - if ob.type == 'MESH' and ob.data.library is None - ] - - if not is_editmode: - USER_ONLY_SELECTED_FACES = False - - if not obList: - raise Exception("error, no selected mesh objects") - - # Convert from being button types - USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) - USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD) - - # Toggle Edit mode - if is_editmode: - bpy.ops.object.mode_set(mode='OBJECT') - # Assume face select mode! an annoying hack to toggle face select mode because Mesh doesn't like faceSelectMode. - - if USER_SHARE_SPACE: - # Sort by data name so we get consistent results - obList.sort(key=lambda ob: ob.data.name) - collected_islandList = [] - - time1 = time.time() - - # Tag as False so we don't operate on the same mesh twice. - for me in bpy.data.meshes: - me.tag = False - - for ob in obList: - me = ob.data - - if me.tag or me.library: - continue - - # Tag as used - me.tag = True - - if not me.uv_layers: # Mesh has no UV Coords, don't bother. - me.uv_layers.new() - - uv_layer = me.uv_layers.active.data - me_verts = list(me.vertices) - - if USER_ONLY_SELECTED_FACES: - meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons) if f.select] - else: - meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)] - - # ======= - # Generate a projection list from face normals, this is meant to be smart :) - - # make a list of face props that are in sync with meshFaces - # Make a Face List that is sorted by area. - # meshFaces = [] - - # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. - meshFaces.sort(key=lambda a: -a.area) - - # remove all zero area faces - while meshFaces and meshFaces[-1].area <= SMALL_NUM: - # Set their UV's to 0,0 - for uv in meshFaces[-1].uv: - uv.zero() - meshFaces.pop() - - if not meshFaces: - continue - - # Smallest first is slightly more efficient, - # but if the user cancels early then its better we work on the larger data. - - # Generate Projection Vecs - # 0d is 1.0 - # 180 IS -0.59846 - - # Initialize projectVecs - if USER_VIEW_INIT: - # Generate Projection - - # We add to this along the way - projectVecs = [Vector(Window.GetViewVector()) @ ob.matrix_world.inverted().to_3x3()] - else: - projectVecs = [] - - newProjectVec = meshFaces[0].no - newProjectMeshFaces = [] # Popping stuffs it up. - - # Pretend that the most unique angle is ages away to start the loop off - mostUniqueAngle = -1.0 - - # This is popped - tempMeshFaces = meshFaces[:] - - # This while only gathers projection vecs, faces are assigned later on. - while 1: - # If there's none there then start with the largest face - - # add all the faces that are close. - for fIdx in range(len(tempMeshFaces) - 1, -1, -1): - # Use half the angle limit so we don't overweight faces towards this - # normal and hog all the faces. - if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: - newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) - - # Add the average of all these faces normals as a projectionVec - averageVec = Vector((0.0, 0.0, 0.0)) - if user_area_weight == 0.0: - for fprop in newProjectMeshFaces: - averageVec += fprop.no - elif user_area_weight == 1.0: - for fprop in newProjectMeshFaces: - averageVec += fprop.no * fprop.area - else: - for fprop in newProjectMeshFaces: - averageVec += fprop.no * ((fprop.area * user_area_weight) + (1.0 - user_area_weight)) - - if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN - projectVecs.append(averageVec.normalized()) - - # Get the next vec! - # Pick the face that's most different to all existing angles :) - mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. - mostUniqueIndex = 0 # dummy - - for fIdx in range(len(tempMeshFaces) - 1, -1, -1): - angleDifference = -1.0 # 180d difference. - - # Get the closest vec angle we are to. - for p in projectVecs: - temp_angle_diff = p.dot(tempMeshFaces[fIdx].no) - - if angleDifference < temp_angle_diff: - angleDifference = temp_angle_diff - - if angleDifference < mostUniqueAngle: - # We have a new most different angle - mostUniqueIndex = fIdx - mostUniqueAngle = angleDifference - - if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: - # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) - # Now weight the vector to all its faces, will give a more direct projection - # if the face its self was not representative of the normal from surrounding faces. - - newProjectVec = tempMeshFaces[mostUniqueIndex].no - newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] - - else: - if len(projectVecs) >= 1: # Must have at least 2 projections - break - - # If there are only zero area faces then its possible - # there are no projectionVecs - if not len(projectVecs): - Draw.PupMenu('error, no projection vecs where generated, 0 area faces can cause this.') - return - - faceProjectionGroupList = [[] for i in range(len(projectVecs))] - - # MAP and Arrange # We know there are 3 or 4 faces here - - for fIdx in range(len(meshFaces) - 1, -1, -1): - fvec = meshFaces[fIdx].no - i = len(projectVecs) - - # Initialize first - bestAng = fvec.dot(projectVecs[0]) - bestAngIdx = 0 - - # Cycle through the remaining, first already done - while i - 1: - i -= 1 - - newAng = fvec.dot(projectVecs[i]) - if newAng > bestAng: # Reverse logic for dotvecs - bestAng = newAng - bestAngIdx = i - - # Store the area for later use. - faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) - - # Cull faceProjectionGroupList, - - # Now faceProjectionGroupList is full of faces that face match the project Vecs list - for i in range(len(projectVecs)): - # Account for projectVecs having no faces. - if not faceProjectionGroupList[i]: - continue - - # Make a projection matrix from a unit length vector. - MatQuat = VectoQuat(projectVecs[i]) - - # Get the faces UV's from the projected vertex. - for f in faceProjectionGroupList[i]: - f_uv = f.uv - for j, v in enumerate(f.v): - f_uv[j][:] = (MatQuat @ v.co).xy - - if USER_SHARE_SPACE: - # Should we collect and pack later? - islandList = getUvIslands(faceProjectionGroupList, me) - collected_islandList.extend(islandList) - - else: - # Should we pack the islands for this 1 object? - islandList = getUvIslands(faceProjectionGroupList, me) - packIslands(islandList) - - # update the mesh here if we need to. - - # We want to pack all in 1 go, so pack now - if USER_SHARE_SPACE: - packIslands(collected_islandList) - - print("Smart Projection time: %.2f" % (time.time() - time1)) - - # aspect correction is only done in edit mode - and only smart unwrap supports currently - if is_editmode: - bpy.ops.object.mode_set(mode='EDIT') - - if use_aspect: - import bmesh - aspect = context.scene.uvedit_aspect(context.active_object) - if aspect[0] > aspect[1]: - aspect[0] = aspect[1] / aspect[0] - aspect[1] = 1.0 - else: - aspect[1] = aspect[0] / aspect[1] - aspect[0] = 1.0 - - bm = bmesh.from_edit_mesh(me) - - uv_act = bm.loops.layers.uv.active - - faces = [f for f in bm.faces if f.select] - - for f in faces: - for l in f.loops: - l[uv_act].uv[0] *= aspect[0] - l[uv_act].uv[1] *= aspect[1] - - dict_matrix.clear() - - -from bpy.props import FloatProperty, BoolProperty - - -class SmartProject(Operator): - """This script projection unwraps the selected faces of a mesh """ \ - """(it operates on all selected mesh objects, and can be used """ \ - """to unwrap selected faces, or all faces)""" - bl_idname = "uv.smart_project" - bl_label = "Smart UV Project" - bl_options = {'REGISTER', 'UNDO'} - - angle_limit: FloatProperty( - name="Angle Limit", - description="Lower for more projection groups, higher for less distortion", - min=1.0, max=89.0, - default=66.0, - ) - island_margin: FloatProperty( - name="Island Margin", - description="Margin to reduce bleed from adjacent islands", - min=0.0, max=1.0, - default=0.0, - ) - user_area_weight: FloatProperty( - name="Area Weight", - description="Weight projections vector by faces with larger areas", - min=0.0, max=1.0, - default=0.0, - ) - use_aspect: BoolProperty( - name="Correct Aspect", - description="Map UVs taking image aspect ratio into account", - default=True, - ) - stretch_to_bounds: BoolProperty( - name="Stretch to UV Bounds", - description="Stretch the final output to texture bounds", - default=True, - ) - - @classmethod - def poll(cls, context): - return context.active_object is not None - - def execute(self, context): - main(context, - self.island_margin, - self.angle_limit, - self.user_area_weight, - self.use_aspect, - self.stretch_to_bounds, - ) - return {'FINISHED'} - - def invoke(self, context, _event): - wm = context.window_manager - return wm.invoke_props_dialog(self) - - -classes = ( - SmartProject, -) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 215c96a5975..b47d4223372 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -1029,7 +1029,7 @@ class ConstraintButtonsSubPanel(Panel): col = layout.column(align=True) col.prop(con, "map_to_z_from", expand=False, text="Z Source Axis") col.prop(con, "to_min_z" + ext, text="Min") - col.prop(con, "to_max_z" + ext, text="Max") + col.prop(con, "to_max_z" + ext, text="Max") layout.prop(con, "mix_mode" + ext, text="Mix") @@ -1396,7 +1396,7 @@ class BONE_PT_bTransformConstraint_from(BoneConstraintPanel, ConstraintButtonsSu def draw(self, context): self.draw_transform_from(context) - + class OBJECT_PT_bTransformConstraint_destination(ObjectConstraintPanel, ConstraintButtonsSubPanel): bl_parent_id = "OBJECT_PT_bTransformConstraint" bl_label = "Map To" diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 4d6ddb55f24..f16528103ff 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -405,6 +405,7 @@ class GPENCIL_MT_cleanup(Menu): layout = self.layout layout.operator("gpencil.frame_clean_loose", text="Delete Loose Points") + layout.operator("gpencil.frame_clean_duplicate", text="Delete Duplicated Frames") if ob.mode != 'PAINT_GPENCIL': layout.operator("gpencil.stroke_merge_by_distance", text="Merge by Distance") diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index c7df2bbb7eb..5f15fa00562 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -647,6 +647,8 @@ def brush_settings(layout, context, brush, popover=False): layout.prop(brush, "pose_smooth_iterations") if brush.pose_deform_type == 'ROTATE_TWIST' and brush.pose_origin_type in {'TOPOLOGY', 'FACE_SETS'}: layout.prop(brush, "pose_ik_segments") + if brush.pose_deform_type == 'SCALE_TRANSLATE': + layout.prop(brush, "use_pose_lock_rotation") layout.prop(brush, "use_pose_ik_anchored") layout.prop(brush, "use_connected_only") layout.prop(brush, "disconnected_distance_max") @@ -655,14 +657,21 @@ def brush_settings(layout, context, brush, popover=False): elif sculpt_tool == 'CLOTH': layout.separator() - layout.prop(brush, "cloth_sim_limit") - layout.prop(brush, "cloth_sim_falloff") + layout.prop(brush, "cloth_simulation_area_type") + if brush.cloth_simulation_area_type == 'LOCAL': + layout.prop(brush, "cloth_sim_limit") + layout.prop(brush, "cloth_sim_falloff") + layout.prop(brush, "use_cloth_pin_simulation_boundary") + layout.separator() layout.prop(brush, "cloth_deform_type") layout.prop(brush, "cloth_force_falloff_type") layout.separator() layout.prop(brush, "cloth_mass") layout.prop(brush, "cloth_damping") + layout.prop(brush, "cloth_constraint_softbody_strength") + layout.separator() + layout.prop(brush, "use_cloth_collision") layout.separator() elif sculpt_tool == 'SCRAPE': @@ -711,6 +720,12 @@ def brush_settings(layout, context, brush, popover=False): col = layout.column() col.prop(brush, "smear_deform_type") + elif sculpt_tool == 'BOUNDARY': + col = layout.column() + col.prop(brush, "boundary_deform_type") + col.prop(brush, "boundary_falloff_type") + col.prop(brush, "boundary_offset") + elif sculpt_tool == 'TOPOLOGY': col = layout.column() col.prop(brush, "slide_deform_type") @@ -1097,6 +1112,45 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): header=True ) +def brush_basic__draw_color_selector(context, layout, brush, gp_settings, props): + tool_settings = context.scene.tool_settings + settings = tool_settings.gpencil_paint + ma = gp_settings.material + + row = layout.row(align=True) + if not gp_settings.use_material_pin: + ma = context.object.active_material + icon_id = 0 + if ma: + icon_id = ma.id_data.preview.icon_id + txt_ma = ma.name + maxw = 25 + if len(txt_ma) > maxw: + txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:] + else: + txt_ma = "" + + sub = row.row() + sub.ui_units_x = 8 + sub.popover( + panel="TOPBAR_PT_gpencil_materials", + text=txt_ma, + icon_value=icon_id, + ) + + row.prop(gp_settings, "use_material_pin", text="") + + if brush.gpencil_tool in {'DRAW', 'FILL'}: + row.separator(factor=1.0) + row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL') + row.prop_enum(settings, "color_mode", 'VERTEXCOLOR', text="", icon='VPAINT_HLT') + sub_row = row.row(align=True) + sub_row.enabled = settings.color_mode == 'VERTEXCOLOR' + sub_row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") + + if props: + row = layout.row(align=True) + row.prop(props, "subdivision") def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False): tool_settings = context.tool_settings @@ -1130,6 +1184,8 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False) # FIXME: tools must use their own UI drawing! elif brush.gpencil_tool == 'FILL': row = layout.row(align=True) + row.prop(gp_settings, "fill_direction", text="", expand=True) + row = layout.row(align=True) row.prop(gp_settings, "fill_leak", text="Leak Size") row = layout.row(align=True) row.prop(brush, "size", text="Thickness") diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index b03f80bd600..a55bd89ca18 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -23,10 +23,10 @@ from bpy.types import ( ) -def rigid_body_warning(layout): +def rigid_body_warning(layout, text): row = layout.row(align=True) row.alignment = 'RIGHT' - row.label(text="Object does not have a Rigid Body") + row.label(text=text, icon='ERROR') class PHYSICS_PT_rigidbody_panel: @@ -49,13 +49,24 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel): layout.use_property_split = True ob = context.object + parent = ob.parent rbo = ob.rigid_body if rbo is None: - rigid_body_warning(layout) + rigid_body_warning(layout, "Object does not have a Rigid Body") return - layout.prop(rbo, "type", text="Type") + if parent is not None and parent.rigid_body is not None: + if parent.rigid_body.collision_shape == 'COMPOUND': + row = layout.row(align=True) + row.alignment = 'RIGHT' + row.label(text="This object is part of a compound shape", icon='INFO') + else: + rigid_body_warning(layout, "Rigid Body can't be child of a non compound Rigid Body") + return + + if parent is None or parent.rigid_body is None: + layout.prop(rbo, "type", text="Type") class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel): @@ -66,6 +77,8 @@ class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel): @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None: + return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): @@ -76,7 +89,7 @@ class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel): rbo = ob.rigid_body if rbo is None: - rigid_body_warning(layout) + rigid_body_warning(layout, "Object does not have a Rigid Body") return col = layout.column() @@ -96,17 +109,32 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel): @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND': + return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): layout = self.layout ob = context.object + parent = ob.parent rbo = ob.rigid_body layout.use_property_split = True layout.prop(rbo, "collision_shape", text="Shape") + if rbo.collision_shape == 'COMPOUND': + if parent is not None and parent.rigid_body is not None and parent.rigid_body.collision_shape == 'COMPOUND': + rigid_body_warning(layout, "Sub compound shapes are not allowed") + else: + found = False + for child in ob.children: + if child.rigid_body is not None: + found = True + break + if not found: + rigid_body_warning(layout, "There are no child rigid bodies") + if rbo.collision_shape in {'MESH', 'CONVEX_HULL'}: layout.prop(rbo, "mesh_source", text="Source") @@ -123,6 +151,8 @@ class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None: + return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): @@ -149,6 +179,8 @@ class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, P @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND': + return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): @@ -180,6 +212,8 @@ class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, P @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None: + return False return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES)) def draw(self, context): @@ -200,6 +234,8 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): @classmethod def poll(cls, context): obj = context.object + if obj.parent is not None and obj.parent.rigid_body is not None: + return False return (obj and obj.rigid_body and obj.rigid_body.type == 'ACTIVE' and (context.engine in cls.COMPAT_ENGINES)) diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index c251d55714f..078b1c9ff38 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -293,7 +293,7 @@ class GRAPH_MT_key(Menu): # Using the modal operation doesn't make sense for this variant # as we do not have a modal mode for it, so just execute it. - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR' layout.operator_context = operator_context diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index b5926692324..faf4036f9b3 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -275,7 +275,7 @@ class NODE_MT_select(Menu): layout.separator() layout.operator("node.select_all").action = 'TOGGLE' - layout.operator("node.select_all", text="Inverse").action = 'INVERT' + layout.operator("node.select_all", text="Invert").action = 'INVERT' layout.operator("node.select_linked_from") layout.operator("node.select_linked_to") @@ -433,7 +433,7 @@ class NODE_MT_context_menu(Menu): layout.operator("node.delete") layout.operator("node.clipboard_copy", text="Copy") layout.operator("node.clipboard_paste", text="Paste") - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("node.delete_reconnect") diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 8dfa182f52d..19c1c2e02c4 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -327,6 +327,7 @@ class SEQUENCER_MT_view(Menu): if is_preview: layout.separator() if st.display_mode == 'IMAGE': + layout.prop(st, "zoom_to_fit") layout.prop(ed, "show_overlay", text="Show Frame Overlay") layout.prop(st, "show_safe_areas", text="Show Safe Areas") layout.prop(st, "show_metadata", text="Show Metadata") @@ -796,7 +797,7 @@ class SEQUENCER_MT_context_menu(Menu): props = layout.operator("wm.call_panel", text="Rename...") props.name = "TOPBAR_PT_name" props.keep_open = False - layout.operator("sequencer.delete", text="Delete...") + layout.operator("sequencer.delete", text="Delete") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index e4cecf3378f..38879d41a64 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1226,22 +1226,32 @@ class _defs_sculpt: @ToolDef.from_fn def mask_border(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("paint.mask_box_gesture") + layout.prop(props, "use_front_faces_only", expand=False) + return dict( idname="builtin.box_mask", label="Box Mask", icon="ops.sculpt.border_mask", widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def mask_lasso(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("paint.mask_lasso_gesture") + layout.prop(props, "use_front_faces_only", expand=False) + return dict( idname="builtin.lasso_mask", label="Lasso Mask", icon="ops.sculpt.lasso_mask", widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn @@ -1257,6 +1267,8 @@ class _defs_sculpt: layout.prop(props, "surface_smooth_current_vertex", expand=False) elif props.type == 'SHARPEN': layout.prop(props, "sharpen_smooth_ratio", expand=False) + layout.prop(props, "sharpen_intensify_detail_strength", expand=False) + layout.prop(props, "sharpen_curvature_smooth_iterations", expand=False) return dict( idname="builtin.mesh_filter", @@ -1276,6 +1288,7 @@ class _defs_sculpt: layout.prop(props, "cloth_mass") layout.prop(props, "cloth_damping") layout.prop(props, "use_face_sets") + layout.prop(props, "use_collisions") return dict( idname="builtin.cloth_filter", @@ -1322,6 +1335,22 @@ class _defs_sculpt: draw_settings=draw_settings, ) + @ToolDef.from_fn + def face_set_edit(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("sculpt.face_set_edit") + layout.prop(props, "mode", expand=False) + layout.prop(props, "modify_hidden") + + return dict( + idname="builtin.face_set_edit", + label="Edit Face Set", + icon="ops.sculpt.face_set_edit", + widget=None, + keymap="3D View Tool: Sculpt, Face Set Edit", + draw_settings=draw_settings, + ) + class _defs_vertex_paint: @@ -1658,6 +1687,29 @@ class _defs_image_uv_sculpt: class _defs_gpencil_paint: @staticmethod + def gpencil_primitive_toolbar(context, layout, tool, props): + paint = context.tool_settings.gpencil_paint + brush = paint.brush + + if brush is None: + return False + + gp_settings = brush.gpencil_settings + + row = layout.row(align=True) + tool_settings = context.scene.tool_settings + settings = tool_settings.gpencil_paint + row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) + + from bl_ui.properties_paint_common import ( + brush_basic_gpencil_paint_settings, + brush_basic__draw_color_selector, + ) + + brush_basic__draw_color_selector(context, layout, brush, gp_settings, props) + brush_basic_gpencil_paint_settings(layout, context, brush, compact=True) + + @staticmethod def generate_from_brushes(context): return generate_from_enum_ex( context, @@ -1684,6 +1736,10 @@ class _defs_gpencil_paint: @ToolDef.from_fn def line(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_line") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.line", label="Line", @@ -1691,10 +1747,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def polyline(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_polyline") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.polyline", label="Polyline", @@ -1702,10 +1763,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def box(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_box") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.box", label="Box", @@ -1713,10 +1779,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def circle(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_circle") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.circle", label="Circle", @@ -1724,10 +1795,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def arc(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_curve") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.arc", label="Arc", @@ -1735,10 +1811,15 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def curve(): + def draw_settings(context, layout, tool): + props = tool.operator_properties("gpencil.primitive_curve") + _defs_gpencil_paint.gpencil_primitive_toolbar(context, layout, tool, props) + return dict( idname="builtin.curve", label="Curve", @@ -1746,6 +1827,7 @@ class _defs_gpencil_paint: cursor='CROSSHAIR', widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn @@ -2385,9 +2467,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): 'OBJECT': [ *_tools_default, - # Disable for 2.90 release. - # None, - # _tools_view3d_add, + None, + _tools_view3d_add, ], 'POSE': [ *_tools_default, @@ -2415,9 +2496,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ], 'EDIT_MESH': [ *_tools_default, - # Disable for 2.90 release. - # None, - # _tools_view3d_add, + None, + _tools_view3d_add, None, ( _defs_edit_mesh.extrude, @@ -2531,6 +2611,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): else () ), None, + _defs_sculpt.face_set_edit, + None, _defs_transform.translate, _defs_transform.rotate, _defs_transform.scale, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 8880d8c5378..c251b4bfcac 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -385,19 +385,7 @@ class _draw_tool_settings_context_mode: if tool is None: return False - # is_paint = True - # FIXME: tools must use their own UI drawing! - if tool.idname in { - "builtin.line", - "builtin.box", - "builtin.circle", - "builtin.arc", - "builtin.curve", - "builtin.polyline", - }: - # is_paint = False - pass - elif tool.idname == "builtin.cutter": + if tool.idname == "builtin.cutter": row = layout.row(align=True) row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold") return False @@ -411,47 +399,16 @@ class _draw_tool_settings_context_mode: gp_settings = brush.gpencil_settings - def draw_color_selector(): - ma = gp_settings.material - row = layout.row(align=True) - if not gp_settings.use_material_pin: - ma = context.object.active_material - icon_id = 0 - if ma: - icon_id = ma.id_data.preview.icon_id - txt_ma = ma.name - maxw = 25 - if len(txt_ma) > maxw: - txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:] - else: - txt_ma = "" - - sub = row.row() - sub.ui_units_x = 8 - sub.popover( - panel="TOPBAR_PT_gpencil_materials", - text=txt_ma, - icon_value=icon_id, - ) - - row.prop(gp_settings, "use_material_pin", text="") - - if brush.gpencil_tool in {'DRAW', 'FILL'}: - row.separator(factor=1.0) - subrow = row.row(align=True) - row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL') - row.prop_enum(settings, "color_mode", 'VERTEXCOLOR', text="", icon='VPAINT_HLT') - sub_row = row.row(align=True) - sub_row.enabled = settings.color_mode == 'VERTEXCOLOR' - sub_row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") - row = layout.row(align=True) tool_settings = context.scene.tool_settings settings = tool_settings.gpencil_paint row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}: - draw_color_selector() + from bl_ui.properties_paint_common import ( + brush_basic__draw_color_selector, + ) + brush_basic__draw_color_selector(context, layout, brush, gp_settings, None) if context.object and brush.gpencil_tool == 'TINT': row.separator(factor=0.4) @@ -986,7 +943,7 @@ class VIEW3D_MT_transform_base(Menu): if context.mode != 'OBJECT': layout.operator("transform.vertex_warp", text="Warp") - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("transform.vertex_random", text="Randomize").offset = 0.1 layout.operator_context = 'INVOKE_REGION_WIN' @@ -1551,7 +1508,7 @@ class VIEW3D_MT_edit_mesh_select_by_trait(Menu): layout.separator() - layout.operator("mesh.select_ungrouped", text="Ungrouped Verts") + layout.operator("mesh.select_ungrouped", text="Ungrouped Vertices") class VIEW3D_MT_edit_mesh_select_more_less(Menu): @@ -1813,7 +1770,7 @@ class VIEW3D_MT_select_edit_lattice(Menu): layout.separator() - layout.operator("lattice.select_ungrouped", text="Ungrouped Verts") + layout.operator("lattice.select_ungrouped", text="Ungrouped Vertices") class VIEW3D_MT_select_edit_armature(Menu): @@ -1940,7 +1897,7 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu): layout.separator() - layout.operator("paint.vert_select_ungrouped", text="Ungrouped Verts") + layout.operator("paint.vert_select_ungrouped", text="Ungrouped Vertices") class VIEW3D_MT_angle_control(Menu): @@ -2058,7 +2015,7 @@ class VIEW3D_MT_edit_metaball_context_menu(Menu): layout.separator() # Remove - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("mball.delete_metaelems", text="Delete") @@ -2333,7 +2290,7 @@ class VIEW3D_MT_object(Menu): layout.separator() - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("object.delete", text="Delete").use_global = False layout.operator("object.delete", text="Delete Global").use_global = True @@ -2597,7 +2554,7 @@ class VIEW3D_MT_object_context_menu(Menu): layout.separator() - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("object.delete", text="Delete").use_global = False @@ -2683,7 +2640,7 @@ class VIEW3D_MT_object_parent(Menu): layout.separator() - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("object.parent_no_inverse_set") layout.operator_context = operator_context_default @@ -2751,6 +2708,8 @@ class VIEW3D_MT_object_quick_effects(Menu): layout.operator("object.quick_explode") layout.operator("object.quick_smoke") layout.operator("object.quick_liquid") + if _context.preferences.experimental.use_new_particle_system: + layout.operator("object.quick_particles") class VIEW3D_MT_object_showhide(Menu): @@ -2772,7 +2731,7 @@ class VIEW3D_MT_make_single_user(Menu): def draw(self, _context): layout = self.layout - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' props = layout.operator("object.make_single_user", text="Object") props.object = True @@ -3686,7 +3645,7 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu): row = layout.row() if is_vert_mode: - col = row.column() + col = row.column(align=True) col.label(text="Vertex Context Menu", icon='VERTEXSEL') col.separator() @@ -3712,7 +3671,7 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu): col.operator("transform.shrink_fatten", text="Shrink/Fatten") col.operator("transform.shear", text="Shear") col.operator("transform.vert_slide", text="Slide Vertices") - col.operator_context = 'EXEC_DEFAULT' + col.operator_context = 'EXEC_REGION_WIN' col.operator("transform.vertex_random", text="Randomize Vertices").offset = 0.1 col.operator("mesh.vertices_smooth", text="Smooth Vertices").factor = 0.5 col.operator_context = 'INVOKE_REGION_WIN' @@ -3736,7 +3695,7 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu): if is_edge_mode: render = context.scene.render - col = row.column() + col = row.column(align=True) col.label(text="Edge Context Menu", icon='EDGESEL') col.separator() @@ -3804,7 +3763,7 @@ class VIEW3D_MT_edit_mesh_context_menu(Menu): col.operator("mesh.delete", text="Delete Edges").type = 'EDGE' if is_face_mode: - col = row.column() + col = row.column(align=True) col.label(text="Face Context Menu", icon='FACESEL') col.separator() @@ -3939,7 +3898,7 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): layout.separator() layout.operator("transform.vert_slide", text="Slide Vertices") - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("mesh.vertices_smooth", text="Smooth Vertices").factor = 0.5 layout.operator("mesh.vertices_smooth_laplacian", text="Smooth Vertices (Laplacian)") layout.operator_context = 'INVOKE_REGION_WIN' @@ -4147,7 +4106,7 @@ class VIEW3D_MT_edit_mesh_normals_select_strength(Menu): class VIEW3D_MT_edit_mesh_normals_set_strength(Menu): - bl_label = "Select by Face Strength" + bl_label = "Set Face Strength" def draw(self, _context): layout = self.layout @@ -4193,7 +4152,7 @@ class VIEW3D_MT_edit_mesh_normals(Menu): layout.operator_context = 'INVOKE_REGION_WIN' layout.operator("transform.rotate_normal", text="Rotate...") layout.operator("mesh.point_normals", text="Point to Target...") - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("mesh.merge_normals", text="Merge") layout.operator("mesh.split_normals", text="Split") @@ -4209,8 +4168,8 @@ class VIEW3D_MT_edit_mesh_normals(Menu): layout.separator() - layout.menu("VIEW3D_MT_edit_mesh_normals_select_strength", text="Select by Face Strength") - layout.menu("VIEW3D_MT_edit_mesh_normals_set_strength", text="Set Face Strength") + layout.menu("VIEW3D_MT_edit_mesh_normals_select_strength") + layout.menu("VIEW3D_MT_edit_mesh_normals_set_strength") class VIEW3D_MT_edit_mesh_shading(Menu): @@ -4660,7 +4619,7 @@ class VIEW3D_MT_edit_meta(Menu): layout.menu("VIEW3D_MT_edit_meta_showhide") - layout.operator_context = 'EXEC_DEFAULT' + layout.operator_context = 'EXEC_REGION_WIN' layout.operator("mball.delete_metaelems", text="Delete") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index e6d27d531be..dfabf5e9d81 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1397,6 +1397,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel): col = layout.column(align=True) if brush is not None: + col.prop(gp_settings, "brush_draw_mode") + col.separator() + if brush.gpencil_tool != 'FILL': col.prop(gp_settings, "input_samples") col.separator() @@ -1425,11 +1428,22 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel): row = col.row(align=True) row.prop(gp_settings, "fill_draw_mode", text="Boundary") row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID') + + col.separator() + row = col.row(align=True) + row.prop(gp_settings, "fill_layer_mode", text="Layers") + col.separator() col.prop(gp_settings, "fill_factor", text="Resolution") if gp_settings.fill_draw_mode != 'STROKE': - col.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes") - col.prop(gp_settings, "fill_threshold", text="Threshold") + col = layout.column(align=False, heading="Ignore Transparent") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(gp_settings, "show_fill", text="") + sub = sub.row(align=True) + sub.active = gp_settings.show_fill + sub.prop(gp_settings, "fill_threshold", text="") class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel): diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 60eb0194a9a..f62c2ead144 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -475,6 +475,12 @@ texture_node_categories = [ ]), ] +def not_implemented_node(idname): + NodeType = getattr(bpy.types, idname) + name = NodeType.bl_rna.name + label = f"{name} (mockup)" + return NodeItem(idname, label=label) + simulation_node_categories = [ # Simulation Nodes SimulationNodeCategory("SIM_OUTPUT", "Output", items=[ @@ -489,12 +495,13 @@ simulation_node_categories = [ ]), SimulationNodeCategory("SIM_EMITTERS", "Emitters", items=[ NodeItem("SimulationNodeParticleMeshEmitter"), - NodeItem("SimulationNodeEmitParticles"), + not_implemented_node("SimulationNodeEmitParticles"), ]), SimulationNodeCategory("SIM_EVENTS", "Events", items=[ NodeItem("SimulationNodeParticleBirthEvent"), NodeItem("SimulationNodeParticleTimeStepEvent"), - NodeItem("SimulationNodeParticleMeshCollisionEvent"), + NodeItem("SimulationNodeAgeReachedEvent"), + not_implemented_node("SimulationNodeParticleMeshCollisionEvent"), ]), SimulationNodeCategory("SIM_FORCES", "Forces", items=[ NodeItem("SimulationNodeForce"), @@ -502,18 +509,19 @@ simulation_node_categories = [ SimulationNodeCategory("SIM_EXECUTE", "Execute", items=[ NodeItem("SimulationNodeSetParticleAttribute"), NodeItem("SimulationNodeExecuteCondition"), - NodeItem("SimulationNodeMultiExecute"), + NodeItem("SimulationNodeKillParticle"), + not_implemented_node("SimulationNodeMultiExecute"), ]), SimulationNodeCategory("SIM_NOISE", "Noise", items=[ - NodeItem("ShaderNodeTexNoise"), - NodeItem("ShaderNodeTexWhiteNoise"), + not_implemented_node("ShaderNodeTexNoise"), + not_implemented_node("ShaderNodeTexWhiteNoise"), ]), SimulationNodeCategory("SIM_COLOR", "Color", items=[ - NodeItem("ShaderNodeMixRGB"), - NodeItem("ShaderNodeInvert"), - NodeItem("ShaderNodeHueSaturation"), - NodeItem("ShaderNodeGamma"), - NodeItem("ShaderNodeBrightContrast"), + not_implemented_node("ShaderNodeMixRGB"), + not_implemented_node("ShaderNodeInvert"), + not_implemented_node("ShaderNodeHueSaturation"), + not_implemented_node("ShaderNodeGamma"), + not_implemented_node("ShaderNodeBrightContrast"), ]), SimulationNodeCategory("SIM_CONVERTER", "Converter", items=[ NodeItem("ShaderNodeMapRange"), @@ -525,12 +533,13 @@ simulation_node_categories = [ NodeItem("ShaderNodeCombineRGB"), NodeItem("ShaderNodeSeparateXYZ"), NodeItem("ShaderNodeCombineXYZ"), - NodeItem("ShaderNodeSeparateHSV"), - NodeItem("ShaderNodeCombineHSV"), + not_implemented_node("ShaderNodeSeparateHSV"), + not_implemented_node("ShaderNodeCombineHSV"), NodeItem("FunctionNodeBooleanMath"), NodeItem("FunctionNodeFloatCompare"), - NodeItem("FunctionNodeSwitch"), + not_implemented_node("FunctionNodeSwitch"), NodeItem("FunctionNodeCombineStrings"), + NodeItem("FunctionNodeRandomFloat"), ]), SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items), SimulationNodeCategory("SIM_LAYOUT", "Layout", items=[ |