2026-03-16

This commit is contained in:
2026-03-17 15:39:39 -06:00
parent 67782275d5
commit 330fed4231
29 changed files with 532 additions and 199 deletions
+5 -5
View File
@@ -10,13 +10,13 @@ D:\Work\9 iClone\Amazon\
D:\Amazon\00_external-files\
N:\1. CHARACTERS\remapping\
[Recent]
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Deliverable\
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\
C:\Program Files (x86)\Steam\steamapps\common\Blender\5.0\scripts\startup\
P:\260217_Jarvis-Defense\Blends\animations\
T:\1 BlenderAssets\
A:\1 Amazon_Active_Projects\1 BlenderAssets\
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\
F:\renders\
P:\260217_Jarvis-Defense\Assets\Blends\Props\
C:\Users\Nathan\Downloads\Shot5\
P:\260217_Jarvis-Defense\Assets\Blends\textures\
P:\260217_Jarvis-Defense\Assets\Blends\textures\3075 Decade Dr\common\
P:\260217_Jarvis-Defense\Assets\
+51 -2
View File
@@ -1,11 +1,60 @@
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18h.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18g.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_3d.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18f.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18e.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18c.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18d.blend
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_10.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_18b.blend
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_3a-b.blend
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_1a.blend
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_1c.blend
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_1d.blend
C:\Users\Nathan\Downloads\P&S_BD2_animation 6d.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6d.blend
C:\Users\Nathan\Downloads\PnS_BD2_animation 6d\UNC_NEXUS_amazon\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.1.blend
C:\Users\Nathan\Downloads\PnS_BD2_animation 6d\UNC_NEXUS_amazon\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Kirk_v4.4.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6c.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8c_part2.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 11a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 9b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 7c.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 5b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 4d.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 3a_part2.blend
F:\jobs\P&S_BD2_animation 8c\P&S_BD2_animation 8c.flamenco.blend
F:\jobs\P&S_BD2_animation 9e\P&S_BD2_animation 9e.flamenco.blend
F:\jobs\P&S_BD2_animation 8b\P&S_BD2_animation 8b.flamenco.blend
F:\jobs\P&S_BD2_animation 8c_part2\P&S_BD2_animation 8c_part2.flamenco.blend
F:\jobs\P&S_BD2_animation 8a\P&S_BD2_animation 8a.flamenco.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8a.blend
T:\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8a.blend
T:\260311_PnS-Beyond-Day-2\Blends\stills\P&S_BD2_animation 8a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8c.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 9e.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 9c.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 9a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 12b_part2.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 12b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 12a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 11b.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part3.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part2.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10a.blend
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part1.blend
P:\260217_Jarvis-Defense\Blends\animations\Shot_4.blend
P:\260217_Jarvis-Defense\Blends\animations\Shot_3_retimed.blend
F:\jobs\Shot_4c\Shot_4.flamenco.blend
F:\jobs\Shot_4e\Shot_4.flamenco.blend
F:\jobs\Shot_4a\Shot_4.flamenco.blend
F:\jobs\Shot_4g\Shot_4.flamenco.blend
P:\260217_Jarvis-Defense\Blends\animations\Shot_4.blend
F:\jobs\Shot_1a-tqpj\Shot_1.flamenco.blend
F:\jobs\Shot_6-4dkh\closeup.flamenco.blend
P:\260217_Jarvis-Defense\Blends\animations\Shot_3_retimed.blend
F:\jobs\Shot_0_5a\Shot_0_5.flamenco.blend
P:\260217_Jarvis-Defense\Blends\animations\closeup.blend
F:\jobs\Shot5c\Shot_Q.flamenco.blend
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
schema_version = "1.0.0"
id = "brushstroke_tools"
version = "1.1.2"
version = "1.2.1"
name = "Brushstroke Tools"
tagline = "Brushstroke painting tools by the Blender Studio"
maintainer = "Simon Thommes <simon@blender.org>"
@@ -20,4 +20,4 @@ copyright = [
]
[permissions]
files = "Read/write brushstroke asset resources from/to disk"
files = "Read/write brushstroke asset resources from/to disk"
@@ -94,6 +94,12 @@ class BSBST_OT_pre_process_brushstroke(bpy.types.Operator):
for prop in props_list:
setattr(context.tool_settings.curve_paint_settings, prop, getattr(tool_settings, prop))
if bpy.app.version >= (5,1):
utils.ensure_resources()
ng_process = bpy.data.node_groups['.brushstroke_tools.draw_processing']
ng_process.asset_mark() # workaround to let Blender register the node tool as an operator with the automatically generated id
ng_process.asset_clear()
return {'FINISHED'}
class BSBST_OT_post_process_brushstroke(bpy.types.Operator):
@@ -119,7 +125,11 @@ class BSBST_OT_post_process_brushstroke(bpy.types.Operator):
if 'BSBST_surface_object' in context.object.keys():
if context.object['BSBST_surface_object']:
self.ng_process.nodes['surface_object'].inputs[0].default_value = context.object['BSBST_surface_object']
bpy.ops.geometry.execute_node_group(name="set_brush_stroke_color", session_uid=self.ng_process.session_uid)
if bpy.app.version < (5,1):
bpy.ops.geometry.execute_node_group(name="set_brush_stroke_color", session_uid=self.ng_process.session_uid)
else:
bpy.ops.geometry._brushstroke_tools_draw_processing()
preserve_draw_settings(context, restore=True)
return {'FINISHED'}
+52 -45
View File
@@ -30,21 +30,18 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
settings.brushstroke_method = self.method
if settings.curve_mode == 'GP':
bpy.ops.object.grease_pencil_add(type='EMPTY')
context.object.name = name
context.object.data.name = name
brushstrokes_object = context.object
context.collection.objects.unlink(brushstrokes_object)
else:
if settings.curve_mode == 'CURVE':
brushstrokes_data = bpy.data.curves.new(name, type='CURVE')
brushstrokes_data.dimensions = '3D'
elif settings.curve_mode == 'CURVES':
brushstrokes_data = bpy.data.hair_curves.new(name)
brushstrokes_object = bpy.data.objects.new(name, brushstrokes_data)
brushstrokes_data = bpy.data.grease_pencils.new(name)
bs_layer = brushstrokes_data.layers.new('Brushstrokes')
bs_layer.frames.new(1)
elif settings.curve_mode == 'CURVE':
brushstrokes_data = bpy.data.curves.new(name, type='CURVE')
brushstrokes_data.dimensions = '3D'
elif settings.curve_mode == 'CURVES':
brushstrokes_data = bpy.data.hair_curves.new(name)
brushstrokes_object = bpy.data.objects.new(name, brushstrokes_data)
# link to surface object's collections (fall back to active collection if all are linked data)
utils.link_to_collections_by_ref(brushstrokes_object, surface_object)
utils.link_to_collections_by_ref(brushstrokes_object, surface_object, unlink=False)
brushstrokes_object.visible_shadow = False
brushstrokes_object['BSBST_version'] = utils.addon_version
@@ -55,21 +52,18 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
def new_flow_object(self, context, name, surface_object):
settings = context.scene.BSBST_settings
if settings.curve_mode == 'GP':
bpy.ops.object.grease_pencil_add(type='EMPTY')
context.object.name = name
context.object.data.name = name
flow_object = context.object
context.collection.objects.unlink(flow_object)
else:
if settings.curve_mode == 'CURVE':
flow_data = bpy.data.curves.new(name, type='CURVE')
flow_data.dimensions = '3D'
elif settings.curve_mode == 'CURVES':
flow_data = bpy.data.hair_curves.new(name)
flow_object = bpy.data.objects.new(name, flow_data)
flow_data = bpy.data.grease_pencils.new(name)
fl_layer = flow_data.layers.new('Flow')
fl_layer.frames.new(1)
elif settings.curve_mode == 'CURVE':
flow_data = bpy.data.curves.new(name, type='CURVE')
flow_data.dimensions = '3D'
elif settings.curve_mode == 'CURVES':
flow_data = bpy.data.hair_curves.new(name)
flow_object = bpy.data.objects.new(name, flow_data)
# link to surface object's collections (fall back to active collection if all are linked data)
utils.link_to_collections_by_ref(flow_object, surface_object)
utils.link_to_collections_by_ref(flow_object, surface_object, unlink=False)
visibility_options = [
'visible_camera',
@@ -112,7 +106,7 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
self.report({"ERROR"}, "Surface Object needs an available UV Map")
return {"CANCELLED"}
name = f'{surface_object.name} - Brushstrokes'
name = utils.bs_name(surface_object.name)
brushstrokes_object = self.new_brushstrokes_object(context, name, surface_object)
flow_is_required = settings.brushstroke_method == 'SURFACE_FILL'
if flow_is_required:
@@ -151,7 +145,9 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
with context.temp_override(**override):
bpy.ops.object.material_slot_add()
brushstrokes_object.material_slots[0].material = preset_material
settings.silent_switch = True
settings.context_material = preset_material
settings.silent_switch = False
brushstrokes_object['BSBST_material'] = settings.context_material
# transfer preset modifiers to new brushstrokes TODO: refactor to deduplicate
@@ -238,7 +234,7 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
mod.show_group_selector = False
# update brushstroke context
utils.find_context_brushstrokes(None)
utils.find_context_brushstrokes(context.scene, context.view_layer.depsgraph)
for i, name in enumerate([bs.name for bs in settings.context_brushstrokes]):
if name == brushstrokes_object.name:
settings.active_context_brushstrokes_index = i
@@ -297,7 +293,7 @@ class BSBST_OT_delete_brushstrokes(bpy.types.Operator):
edit_toggle = settings.edit_toggle
settings.edit_toggle = False
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
settings.edit_toggle = edit_toggle
return {"CANCELLED"}
@@ -313,7 +309,7 @@ class BSBST_OT_delete_brushstrokes(bpy.types.Operator):
if surface_object:
context.view_layer.objects.active = surface_object
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if bs_ob:
context.view_layer.objects.active = bs_ob
bs_ob.select_set(True)
@@ -346,7 +342,7 @@ class BSBST_OT_duplicate_brushstrokes(bpy.types.Operator):
def execute(self, context):
settings = context.scene.BSBST_settings
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
return {"CANCELLED"}
@@ -410,7 +406,7 @@ class BSBST_OT_copy_brushstrokes(bpy.types.Operator):
def execute(self, context):
settings = context.scene.BSBST_settings
active_surface_object = utils.get_surface_object(utils.get_active_context_brushstrokes_object(context))
active_surface_object = utils.get_surface_object(utils.get_active_context_brushstrokes_object(context.scene))
surface_objects = [ob for ob in context.selected_objects
if ob.type=='MESH'
@@ -423,7 +419,7 @@ class BSBST_OT_copy_brushstrokes(bpy.types.Operator):
bs_objects = [bpy.data.objects.get(bs.name) for bs in settings.context_brushstrokes]
bs_objects = [bs for bs in bs_objects if bs]
else:
bs_objects = [utils.get_active_context_brushstrokes_object(context)]
bs_objects = [utils.get_active_context_brushstrokes_object(context.scene)]
if not bs_objects:
return {"CANCELLED"}
@@ -450,6 +446,17 @@ class BSBST_OT_copy_brushstrokes(bpy.types.Operator):
# remap surface pointers and context linked data TODO: refactor to deduplicate
for ob in new_bs:
utils.link_to_collections_by_ref(ob, surface_object)
# if it's still using the default name initialize names again
if utils.split_id_name(ob.name)[0] == utils.bs_name(active_surface_object.name):
if utils.is_flow_object(ob):
ob.name = utils.flow_name(utils.bs_name(surface_object.name))
else:
ob.name = utils.bs_name(surface_object.name)
elif ob.name.startswith(active_surface_object.name):
ob.name = f"{surface_object.name}{ob.name[len(active_surface_object.name):]}"
ob.parent = surface_object
utils.set_surface_object(ob, surface_object)
@@ -504,16 +511,16 @@ class BSBST_OT_select_surface(bpy.types.Operator):
return bool(settings.context_brushstrokes)
def execute(self, context):
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
return {"CANCELLED"}
surface_object = getattr(bs_ob, '["BSBST_surface_object"]', None)
if not surface_object:
return {"CANCELLED"}
bpy.context.view_layer.objects.active = surface_object
if not context.mode == 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.view_layer.objects.active = surface_object
for ob in bpy.data.objects:
ob.select_set(False)
surface_object.select_set(True)
@@ -537,7 +544,7 @@ class BSBST_OT_assign_surface(bpy.types.Operator):
return bool(settings.context_brushstrokes)
def execute(self, context):
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
return {"CANCELLED"}
@@ -555,7 +562,7 @@ class BSBST_OT_assign_surface(bpy.types.Operator):
layout.prop_search(self, 'surface_object', bpy.data, 'objects')
def invoke(self, context, event):
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
surf_ob = utils.get_surface_object(bs_ob)
if surf_ob:
self.surface_object = surf_ob.name
@@ -632,7 +639,7 @@ class BSBST_OT_copy_flow(bpy.types.Operator):
return bool(settings.context_brushstrokes)
def execute(self, context):
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
flow_ob_old = utils.get_flow_object(bs_ob)
if not bs_ob:
return {"CANCELLED"}
@@ -670,7 +677,7 @@ class BSBST_OT_copy_flow(bpy.types.Operator):
def invoke(self, context, event):
settings = context.scene.BSBST_settings
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
for i in range(len(self.bs_list)):
self.bs_list.remove(0)
@@ -721,7 +728,7 @@ class BSBST_OT_switch_deformable(bpy.types.Operator):
bs_objects = [bpy.data.objects.get(bs.name) for bs in settings.context_brushstrokes]
bs_objects = [bs for bs in bs_objects if bs]
else:
bs_objects = [utils.get_active_context_brushstrokes_object(context)]
bs_objects = [utils.get_active_context_brushstrokes_object(context.scene)]
if not bs_objects:
return {"CANCELLED"}
@@ -762,7 +769,7 @@ class BSBST_OT_switch_animated(bpy.types.Operator):
bs_objects = [bpy.data.objects.get(bs.name) for bs in settings.context_brushstrokes]
bs_objects = [bs for bs in bs_objects if bs]
else:
bs_objects = [utils.get_active_context_brushstrokes_object(context)]
bs_objects = [utils.get_active_context_brushstrokes_object(context.scene)]
if not bs_objects:
return {"CANCELLED"}
@@ -963,7 +970,7 @@ class BSBST_OT_make_preset(bpy.types.Operator):
@classmethod
def poll(cls, context):
return bool(utils.get_active_context_brushstrokes_object(context))
return bool(utils.get_active_context_brushstrokes_object(context.scene))
def execute(self, context):
@@ -977,7 +984,7 @@ class BSBST_OT_make_preset(bpy.types.Operator):
settings.preset_object.modifiers.remove(mod)
# transfer brushstrokes modifiers to preset
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
return {"CANCELLED"}
for mod in bs_ob.modifiers:
@@ -1098,7 +1105,7 @@ class BSBST_OT_brushstrokes_toggle_attribute(bpy.types.Operator):
edit_toggle = settings.edit_toggle
settings.edit_toggle = False
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
settings.edit_toggle = edit_toggle
return {"CANCELLED"}
@@ -25,7 +25,7 @@ def update_brushstroke_method(self, context):
preset_object = bpy.data.objects.get(preset_name)
settings.preset_object = preset_object
style_object = utils.get_active_context_brushstrokes_object(context)
style_object = utils.get_active_context_brushstrokes_object(context.scene)
if not style_object:
style_object = preset_object
@@ -45,7 +45,7 @@ def update_context_material(self, context):
if settings.silent_switch:
return
style_object = utils.get_active_context_brushstrokes_object(context)
style_object = utils.get_active_context_brushstrokes_object(context.scene)
if not style_object:
style_object = settings.preset_object
if not style_object:
@@ -119,7 +119,14 @@ def get_active_context_brushstrokes_index(self):
return self["active_context_brushstrokes_index"]
def set_active_context_brushstrokes_index(self, value):
settings = bpy.context.scene.BSBST_settings
scene = self.id_data
settings = scene.BSBST_settings
for window in bpy.context.window_manager.windows:
if window.scene == scene:
view_layer = window.view_layer
active_object = view_layer.objects.active
if not settings.context_brushstrokes:
if not settings.preset_object:
return
@@ -136,12 +143,11 @@ def set_active_context_brushstrokes_index(self, value):
return
if not bs_ob:
return
if not bpy.context.object:
if not active_object:
return
view_layer = bpy.context.view_layer
if bpy.context.object.visible_get(view_layer = view_layer):
if active_object.visible_get(view_layer = view_layer):
bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.view_layer.objects.active = bs_ob
view_layer.objects.active = bs_ob
if bs_ob.visible_get(view_layer = view_layer):
bpy.ops.object.mode_set(mode='OBJECT')
for ob in bpy.data.objects:
@@ -257,7 +263,7 @@ class BSBST_Settings(bpy.types.PropertyGroup):
gpv3 = bpy.context.preferences.experimental.use_grease_pencil_version3
except:
v0, v1, v3 = bpy.app.version
gpv3 = v0 >= 4 and v1 >= 3
gpv3 = v0 >= 4 or (v0 == 4 and v1 >= 3)
curve_mode: bpy.props.EnumProperty(default='CURVES',
items= [('CURVE', 'Legacy', 'Use legacy curve type (Limited Support)', 'CURVE_DATA', 0),\
('CURVES', 'Curves', 'Use hair curves (Fully supported)', 'CURVES_DATA', 1),
+16 -13
View File
@@ -536,7 +536,7 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
row = style_panel.row()
row_edit = row.row(align=True)
row_edit.operator('brushstroke_tools.select_surface', icon='OUTLINER_OB_SURFACE', text='')
bs_ob = utils.get_active_context_brushstrokes_object(context)
bs_ob = utils.get_active_context_brushstrokes_object(context.scene)
text = 'Edit Flow' if getattr(bs_ob, '["BSBST_method"]', None)=='SURFACE_FILL' else 'Edit Brushstrokes'
row_edit.operator('brushstroke_tools.edit_brushstrokes', icon='GREASEPENCIL', text = text)
row_edit.prop(settings, 'edit_toggle', icon='RESTRICT_SELECT_OFF' if settings.edit_toggle else 'RESTRICT_SELECT_ON', icon_only=True)
@@ -549,15 +549,15 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
class BSBST_MT_PIE_brushstroke_data_marking(bpy.types.Menu):
bl_idname= "BSBST_MT_PIE_brushstroke_data_marking"
bl_label = "Mark Brushstroke Flow"
bl_label = "Mark Brushstroke Data"
items = {
"Brush Flow - Mark": ['FORCE_WIND'],
"Brush Flow - Clear": ['NONE'],
"Brush Break - Mark": ['MOD_PHYSICS'],
"Brush Break - Clear": ['NONE'],
"Brush Ignore - Mark": ['X'],
"Brush Ignore - Clear": ['NONE'],
"Brush Flow - Mark": ['geometry.brush_flow_mark','FORCE_WIND'],
"Brush Flow - Clear": ['geometry.brush_flow_clear','NONE'],
"Brush Break - Mark": ['geometry.brush_break_mark','MOD_PHYSICS'],
"Brush Break - Clear": ['geometry.brush_break_clear','NONE'],
"Brush Ignore - Mark": ['geometry.brush_ignore_mark','X'],
"Brush Ignore - Clear": ['geometry.brush_ignore_clear','NONE'],
}
def draw(self, context):
@@ -567,11 +567,14 @@ class BSBST_MT_PIE_brushstroke_data_marking(bpy.types.Menu):
for name, info in self.items.items():
pie.alert=True
op = pie.operator("geometry.execute_node_group", text=name, icon=info[0])
op.asset_library_type='CUSTOM'
op.asset_library_identifier=utils.asset_lib_name
op.relative_asset_identifier=f"core/brushstroke_tools-resources.blend/NodeTree/{name}"
if bpy.app.version < (5,1):
op = pie.operator("geometry.execute_node_group", text=name, icon=info[1])
op.asset_library_type='CUSTOM'
op.asset_library_identifier=utils.asset_lib_name
op.relative_asset_identifier=f"core/brushstroke_tools-resources.blend/NodeTree/{name}"
else:
op = pie.operator(info[0], text=name, icon=info[1])
class BSBST_OT_brushstroke_data_marking(bpy.types.Operator):
"""
Call pie menu for operators to mark brushstroke data on the surface mesh
@@ -37,9 +37,8 @@ linkable_sockets = [
asset_lib_name = 'Brushstroke Tools Library'
@persistent
def find_context_brushstrokes(dummy):
context = bpy.context
settings = context.scene.BSBST_settings
def find_context_brushstrokes(scene, depsgraph):
settings = scene.BSBST_settings
edit_toggle = settings.edit_toggle
settings.edit_toggle = False
@@ -49,7 +48,7 @@ def find_context_brushstrokes(dummy):
# identify context brushstrokes
for el in range(len(settings.context_brushstrokes)):
settings.context_brushstrokes.remove(0)
context_object = context.object
context_object = depsgraph.view_layer.objects.active
if not is_brushstrokes_object(context_object):
bs_ob = is_flow_object(context_object)
if bs_ob:
@@ -97,12 +96,11 @@ def find_context_brushstrokes(dummy):
settings.edit_toggle = edit_toggle
@persistent
def refresh_preset(dummy):
context = bpy.context
settings = context.scene.BSBST_settings
def refresh_preset(scene, depsgraph):
settings = scene.BSBST_settings
if not settings:
return
for ob in [settings.preset_object, get_active_context_brushstrokes_object(context)]:
for ob in [settings.preset_object, get_active_context_brushstrokes_object(scene)]:
if not ob:
continue
for mod in ob.modifiers:
@@ -313,6 +311,25 @@ def write_lib_version(dir: Path = None):
with open(dir.joinpath(".version"), "w") as file:
file.write(str(addon_version))
def get_file_blend_version(path: Path):
with open(path, "rb") as f:
prefix = f.read(4)
f.seek(0)
if prefix.startswith(b"BLENDER"):
header = f.read(12)
elif prefix == b"\x28\xb5\x2f\xfd": # zstd
dctx = zstd.ZstdDecompressor()
with dctx.stream_reader(f) as reader:
header = reader.read(12)
else:
raise ValueError("Unknown blend format")
version = header[9:12].decode()
return int(version[0]), int(version[1:])
def copy_resources_to_dir(tgt_dir = ''):
source_dir = get_addon_directory().joinpath('assets')
if not tgt_dir:
@@ -545,8 +562,21 @@ def find_brush_style_by_name(name: str):
return brush_style
return None
def link_to_collections_by_ref(obj, ref_obj):
def link_to_collections_by_ref(obj, ref_obj, unlink=True):
col_list = []
if unlink:
for col in obj.users_collection:
if col.library:
continue
col_list += [col]
if col_list:
for col in col_list:
col.objects.unlink(obj)
col_list = []
for col in ref_obj.users_collection:
if col.library:
continue
@@ -754,8 +784,8 @@ def context_brushstrokes(context):
settings = context.scene.BSBST_settings
return settings.context_brushstrokes
def get_active_context_brushstrokes_object(context):
settings = context.scene.BSBST_settings
def get_active_context_brushstrokes_object(scene):
settings = scene.BSBST_settings
if not settings.context_brushstrokes:
return None
bs = settings.context_brushstrokes[settings.active_context_brushstrokes_index]
@@ -765,19 +795,22 @@ def get_active_context_brushstrokes_object(context):
def get_active_context_surface_object(context):
if not context.object:
return None
bs_ob = get_active_context_brushstrokes_object(context)
bs_ob = get_active_context_brushstrokes_object(context.scene)
if bs_ob:
return get_surface_object(bs_ob)
if context.object.type == 'MESH':
return context.object
def flow_name(name):
return f'{name}-FLOW'
def bs_name(surf_name: str) -> str:
return f'{surf_name} - Brushstrokes'
def flow_name(bs_name: str) -> str:
return f'{bs_name}-FLOW'
def edit_active_brushstrokes(context):
context.view_layer.depsgraph.update()
bs_ob = get_active_context_brushstrokes_object(context)
bs_ob = get_active_context_brushstrokes_object(context.scene)
if not bs_ob:
return {"CANCELLED"}
@@ -33,7 +33,7 @@
"id": "rainclouds_bulk_scene_tools",
"name": "Raincloud's Bulk Scene Tools",
"tagline": "Bulk utilities for optimizing scene data",
"version": "0.16.0",
"version": "0.17.0",
"type": "add-on",
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
"license": [
@@ -49,9 +49,9 @@
"Workflow",
"Materials"
],
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.16.0/Rainys_Bulk_Scene_Tools.v0.16.0.zip",
"archive_size": 80251,
"archive_hash": "sha256:3e6fafe11caa39e48b94288c12b2a88e521c928955a854ffdd1bd0936e6bc70a"
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
"archive_size": 80981,
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
},
{
"schema_version": "1.0.0",
@@ -0,0 +1,100 @@
{
"version": "v1",
"blocklist": [],
"data": [
{
"schema_version": "1.0.0",
"id": "basedplayblast",
"name": "BasedPlayblast",
"tagline": "Easily create playblasts from Blender and Flamenco",
"version": "2.6.3",
"type": "add-on",
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
"license": [
"GPL-3.0-or-later"
],
"blender_version_min": "4.2.0",
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
"permissions": {
"files": "Import/export files and data"
},
"tags": [
"Animation",
"Render",
"Workflow",
"Video"
],
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
"archive_size": 49732,
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
},
{
"schema_version": "1.0.0",
"id": "rainclouds_bulk_scene_tools",
"name": "Raincloud's Bulk Scene Tools",
"tagline": "Bulk utilities for optimizing scene data",
"version": "0.17.0",
"type": "add-on",
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
"license": [
"GPL-3.0-or-later"
],
"blender_version_min": "4.2.0",
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
"permissions": {
"files": "Read and write external resources referenced by scenes"
},
"tags": [
"Scene",
"Workflow",
"Materials"
],
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
"archive_size": 80981,
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
},
{
"schema_version": "1.0.0",
"id": "atomic_data_manager",
"name": "Atomic Data Manager",
"tagline": "Smart cleanup and inspection of Blender data-blocks",
"version": "2.5.0",
"type": "add-on",
"maintainer": "RaincloudTheDragon",
"license": [
"GPL-3.0-or-later"
],
"blender_version_min": "4.2.0",
"tags": [
"utility",
"management",
"cleanup"
],
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.5.0/Atomic_Data_Manager.v2.5.0.zip",
"archive_size": 114674,
"archive_hash": "sha256:4b4834ed3910a428d4cb01f1891247ad80089b6c5324fc27c6862b09e81ff1c1"
},
{
"schema_version": "1.0.0",
"id": "sheepit_project_submitter",
"name": "SheepIt Project Submitter",
"tagline": "Submit projects to SheepIt render farm",
"version": "0.0.7",
"type": "add-on",
"maintainer": "RaincloudTheDragon",
"license": [
"GPL-3.0-or-later"
],
"blender_version_min": "3.0.0",
"tags": [
"render",
"farm",
"submission",
"utility"
],
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.7/SheepIt_Project_Submitter.v0.0.7.zip",
"archive_size": 47250,
"archive_hash": "sha256:cb8dee48c45cc51dd8237981f4ab96d97d476b547c8c640606e9bbfd0390a055"
}
]
}
@@ -3,7 +3,7 @@ schema_version = "1.0.0"
id = "rainclouds_bulk_scene_tools"
name = "Raincloud's Bulk Scene Tools"
tagline = "Bulk utilities for optimizing scene data"
version = "0.16.0"
version = "0.17.0"
type = "add-on"
maintainer = "RaincloudTheDragon <raincloudthedragon@gmail.com>"
@@ -1,3 +1,6 @@
# v0.17.0 2026-03-13
- Remove Action FU: new operator in Animation Data section—clears fake users from all actions so only used animations are kept
# v0.16.0 2026-01-15
- Delete Single Keyframe Actions: Blender 5.0 compatible (action layers/strips/channelbags); skip actions from linked libraries
- Find Material Users: removed (issue #14; use Atomic or DBU)
@@ -0,0 +1,24 @@
import bpy
class RemoveActionFakeUsers(bpy.types.Operator):
"""Remove fake users from all actions so only used animations are kept on save"""
bl_idname = "bst.remove_action_fake_users"
bl_label = "Remove Action FU"
bl_description = "Remove fake users from all actions so only used animations are kept"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
actions = bpy.data.actions
cleared_count = 0
for action in actions:
if getattr(action, "library", None) is not None:
continue
if action.use_fake_user:
action.use_fake_user = False
cleared_count += 1
print(f"Removed fake user from action '{action.name}'")
self.report({'INFO'}, f"Removed fake users from {cleared_count} actions")
return {'FINISHED'}
@@ -6,6 +6,7 @@ from ..ops.spawn_scene_structure import SpawnSceneStructure
from ..ops.delete_single_keyframe_actions import DeleteSingleKeyframeActions
from ..ops.remove_unused_material_slots import RemoveUnusedMaterialSlots
from ..ops.convert_relations_to_constraint import ConvertRelationsToConstraint
from ..ops.remove_action_fake_users import RemoveActionFakeUsers
from ..ops.white_world import WhiteWorld
from ..utils import compat
@@ -56,6 +57,8 @@ class RBST_SceneGen_PT_BulkSceneGeneral(bpy.types.Panel):
box = layout.box()
box.label(text="Animation Data")
row = box.row(align=True)
row.operator("bst.remove_action_fake_users", text="Remove Action FU", icon='FAKE_USER_OFF')
row = box.row(align=True)
row.operator("bst.delete_single_keyframe_actions", text="Delete Single Keyframe Actions", icon='ANIM_DATA')
row = box.row(align=True)
row.operator("bst.convert_relations_to_constraint", text="Convert Relations to Constraint", icon_value=405)
@@ -71,6 +74,7 @@ classes = (
DeleteSingleKeyframeActions,
RemoveUnusedMaterialSlots,
ConvertRelationsToConstraint,
RemoveActionFakeUsers,
)
# Registration
@@ -1,5 +1,5 @@
{
"last_check": "2026-03-06 10:02:06.473451",
"last_check": "2026-03-16 11:19:55.639825",
"backup_date": "January-12-2026",
"update_ready": false,
"ignore": false,
@@ -3,7 +3,7 @@ schema_version = "1.0.0"
id = "dynamiclinkmanager"
name = "Dynamic Link Manager"
tagline = "Character migrator and linked library tools"
version = "0.2.0"
version = "0.3.0"
type = "add-on"
# Optional: Semantic Versioning
@@ -482,14 +482,36 @@ def run_retarg_relatives(orig, rep, rep_descendants, orig_to_rep):
for ob in candidates:
if ob.parent == orig:
ob.parent = rep
for c in getattr(ob, "constraints", []):
if getattr(c, "target", None) == orig:
c.target = rep
if ob.type == "MESH" and ob.modifiers:
for m in ob.modifiers:
if getattr(m, "object", None) == orig:
m.object = rep
# Retarget constraints on ALL objects (including orig hierarchy like eyes)
for ob in bpy.data.objects:
for c in getattr(ob, "constraints", []):
if getattr(c, "target", None) == orig:
c.target = rep
# Retarget bone constraints on ALL armatures (other characters, etc.)
for ob in bpy.data.objects:
if ob.type != "ARMATURE" or not ob.pose:
continue
for pbone in ob.pose.bones:
for c in pbone.constraints:
if getattr(c, "target", None) == orig:
c.target = rep
# Camera DOF: retarget focus_object from orig to rep
for ob in bpy.data.objects:
if ob.type != 'CAMERA':
continue
camera = ob.data
if not camera.dof:
continue
if camera.dof.focus_object == orig:
camera.dof.focus_object = rep
def _base_body_name_match(ob):
"""True if object looks like the base body mesh (MESH, name has body+base)."""
@@ -3,7 +3,7 @@
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
"""Tweak tools: add/remove/bake COPY_TRANSFORMS on Rigify arm/leg tweak bones."""
"""Tweak tools: add/remove/bake COPY_TRANSFORMS on Rigify tweak bones (arm, leg, or all)."""
import bpy
@@ -22,7 +22,7 @@ TWEAK_CONSTRAINT_NAME = "Copy from Original"
def get_tweak_bones(armature, limb):
"""Return list of tweak bone names that exist on armature. limb in 'arm', 'leg', 'both'."""
"""Return list of tweak bone names that exist on armature. limb in 'arm', 'leg', 'body', 'both'."""
if not armature or armature.type != "ARMATURE" or not armature.pose:
return []
bones = armature.pose.bones
@@ -30,8 +30,20 @@ def get_tweak_bones(armature, limb):
names = ARM_TWEAK_BONES
elif limb == "leg":
names = LEG_TWEAK_BONES
elif limb == "body":
# Body/torso tweaks: tweak_spine, spine_fk, etc. (no arm/leg)
arm_leg_names = set(ARM_TWEAK_BONES + LEG_TWEAK_BONES)
names = [
b.name for b in bones
if ("tweak" in b.name.lower() or "spine_fk" in b.name.lower())
and b.name not in arm_leg_names
]
elif limb == "both":
names = ARM_TWEAK_BONES + LEG_TWEAK_BONES
# ALL tweak bones: any bone with "tweak" or "spine_fk" in the name
names = [
b.name for b in bones
if "tweak" in b.name.lower() or "spine_fk" in b.name.lower()
]
else:
return []
return [n for n in names if n in bones]
@@ -101,7 +113,7 @@ def bake_tweak_constraints(context, orig, rep, limb, track_name, post_clean):
# Select only tweak bones on rep
bpy.ops.pose.select_all(action="DESELECT")
for name in names:
rep.pose.bones[name].bone.select = True
rep.pose.bones[name].select = True
# Bake
try:
@@ -735,10 +735,72 @@ class DLM_OT_tweak_bake_leg(Operator):
return {"CANCELLED"}
class DLM_OT_tweak_add_body(Operator):
bl_idname = "dlm.tweak_add_body"
bl_label = "Add Body Tweaks"
bl_description = "Add tweak bone constraints to body/torso bones (spine, no arm/leg)"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return _tweak_poll(context)
def execute(self, context):
orig, rep = _get_migrator_pair(context)
from ..ops import tweak_tools
tweak_tools.add_tweak_constraints(orig, rep, "body")
self.report({"INFO"}, "Body tweak constraints added.")
return {"FINISHED"}
class DLM_OT_tweak_remove_body(Operator):
bl_idname = "dlm.tweak_remove_body"
bl_label = "Remove Body Tweaks"
bl_description = "Remove body/torso tweak constraints from the replacement character"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return _tweak_poll(context)
def execute(self, context):
orig, rep = _get_migrator_pair(context)
from ..ops import tweak_tools
n = tweak_tools.remove_tweak_constraints(orig, rep, "body")
self.report({"INFO"}, f"Removed {n} body tweak constraints.")
return {"FINISHED"}
class DLM_OT_tweak_bake_body(Operator):
bl_idname = "dlm.tweak_bake_body"
bl_label = "Bake Body Tweaks"
bl_description = "Bake body/torso tweak constraints to keyframes and optionally remove constraints"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return _tweak_poll(context)
def execute(self, context):
orig, rep = _get_migrator_pair(context)
props = context.scene.dynamic_link_manager
from ..ops import tweak_tools
ok, msg = tweak_tools.bake_tweak_constraints(
context, orig, rep, "body",
getattr(props, "tweak_nla_track_name", "") or "",
getattr(props, "tweak_bake_post_clean", False),
)
if ok:
self.report({"INFO"}, msg)
return {"FINISHED"}
self.report({"ERROR"}, msg)
return {"CANCELLED"}
class DLM_OT_tweak_add_both(Operator):
bl_idname = "dlm.tweak_add_both"
bl_label = "Add Arm & Leg Tweaks"
bl_description = "Add tweak bone constraints to both arm and leg bones"
bl_label = "Add All Tweaks"
bl_description = "Add tweak bone constraints to all tweak bones (arm, leg, body)"
bl_options = {"REGISTER", "UNDO"}
@classmethod
@@ -749,14 +811,14 @@ class DLM_OT_tweak_add_both(Operator):
orig, rep = _get_migrator_pair(context)
from ..ops import tweak_tools
tweak_tools.add_tweak_constraints(orig, rep, "both")
self.report({"INFO"}, "Arm & leg tweak constraints added.")
self.report({"INFO"}, "All tweak constraints added.")
return {"FINISHED"}
class DLM_OT_tweak_remove_both(Operator):
bl_idname = "dlm.tweak_remove_both"
bl_label = "Remove Arm & Leg Tweaks"
bl_description = "Remove all arm and leg tweak constraints from the replacement character"
bl_label = "Remove All Tweaks"
bl_description = "Remove all tweak constraints from the replacement character"
bl_options = {"REGISTER", "UNDO"}
@classmethod
@@ -773,8 +835,8 @@ class DLM_OT_tweak_remove_both(Operator):
class DLM_OT_tweak_bake_both(Operator):
bl_idname = "dlm.tweak_bake_both"
bl_label = "Bake Arm & Leg Tweaks"
bl_description = "Bake all arm and leg tweak constraints to keyframes and optionally remove constraints"
bl_label = "Bake All Tweaks"
bl_description = "Bake all tweak constraints (arm, leg, body) to keyframes and optionally remove constraints"
bl_options = {"REGISTER", "UNDO"}
@classmethod
@@ -825,6 +887,9 @@ OPERATOR_CLASSES = [
DLM_OT_tweak_add_leg,
DLM_OT_tweak_remove_leg,
DLM_OT_tweak_bake_leg,
DLM_OT_tweak_add_body,
DLM_OT_tweak_remove_body,
DLM_OT_tweak_bake_body,
DLM_OT_tweak_add_both,
DLM_OT_tweak_remove_both,
DLM_OT_tweak_bake_both,
@@ -119,9 +119,13 @@ class DLM_PT_main_panel(Panel):
row.operator("dlm.tweak_remove_leg", text="Remove Leg", icon="X")
row.operator("dlm.tweak_bake_leg", text="Bake Leg", icon="KEYFRAME")
row = tweak_box.row(align=True)
row.operator("dlm.tweak_add_both", text="Add Both", icon="CONSTRAINT_BONE")
row.operator("dlm.tweak_remove_both", text="Remove Both", icon="X")
row.operator("dlm.tweak_bake_both", text="Bake Both", icon="KEYFRAME")
row.operator("dlm.tweak_add_body", text="Add Body", icon="CONSTRAINT_BONE")
row.operator("dlm.tweak_remove_body", text="Remove Body", icon="X")
row.operator("dlm.tweak_bake_body", text="Bake Body", icon="KEYFRAME")
row = tweak_box.row(align=True)
row.operator("dlm.tweak_add_both", text="Add All", icon="CONSTRAINT_BONE")
row.operator("dlm.tweak_remove_both", text="Remove All", icon="X")
row.operator("dlm.tweak_bake_both", text="Bake All", icon="KEYFRAME")
row = tweak_box.row()
row.prop(props, "tweak_nla_track_name", text="NLA track")
row = tweak_box.row()
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+64 -74
View File
@@ -1,4 +1,4 @@
keyconfig_version = (4, 3, 29)
keyconfig_version = (5, 0, 118)
keyconfig_data = \
[("3D View",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
@@ -1519,11 +1519,6 @@ keyconfig_data = \
),
("anim.change_frame", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
("action.duplicate_move", {"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True}, None),
("action.keymove",
{"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True},
{ "active":False,
},
),
("action.keymove",
{"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True},
{ "active":False,
@@ -1591,11 +1586,7 @@ keyconfig_data = \
],
},
),
("screen.animation_play",
{"type": 'SPACE', "value": 'PRESS', "repeat": True},
{ "active":False,
},
),
("screen.animation_play", {"type": 'V', "value": 'PRESS', "alt": True, "repeat": True}, None),
("screen.animation_play",
{"type": 'SPACE', "value": 'PRESS', "shift": True, "ctrl": True, "repeat": True},
{"properties":
@@ -1956,38 +1947,10 @@ keyconfig_data = \
("Grease Pencil Stroke Paint (Draw brush)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items":
[("gpencil.draw",
{"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties":
[("mode", 'DRAW'),
("wait_for_input", False),
],
},
),
("gpencil.draw",
{"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties":
[("mode", 'DRAW'),
("wait_for_input", False),
],
},
),
("gpencil.draw",
{"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True},
{"properties":
[("mode", 'DRAW_STRAIGHT'),
("wait_for_input", False),
],
},
),
("gpencil.draw",
{"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties":
[("mode", 'ERASER'),
("wait_for_input", False),
],
},
),
[("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, None),
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True, "alt": True}, None),
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
("gpencil.draw", {"type": 'O', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'J', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'J', "value": 'PRESS', "alt": True}, None),
@@ -2002,14 +1965,7 @@ keyconfig_data = \
("gpencil.draw", {"type": 'M', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'C', "value": 'PRESS'}, None),
("gpencil.draw", {"type": 'C', "value": 'PRESS', "alt": True}, None),
("gpencil.draw",
{"type": 'ERASER', "value": 'PRESS'},
{"properties":
[("mode", 'ERASER'),
("wait_for_input", False),
],
},
),
("gpencil.draw", {"type": 'ERASER', "value": 'PRESS'}, None),
("gpencil.select_box", {"type": 'B', "value": 'PRESS'}, None),
("gpencil.select_lasso", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG', "ctrl": True, "alt": True}, None),
],
@@ -2838,11 +2794,9 @@ keyconfig_data = \
{ "active":False,
},
),
("wm.call_menu",
{"type": 'DEL', "value": 'PRESS', "repeat": True},
{"properties":
[("name", 'VIEW3D_MT_edit_mesh_delete'),
],
("object.swapmode",
{"type": 'MIDDLEMOUSE', "value": 'DOUBLE_CLICK'},
{ "active":False,
},
),
("object.swapmode",
@@ -2850,6 +2804,23 @@ keyconfig_data = \
{ "active":False,
},
),
("object.swapmode",
{"type": 'MIDDLEMOUSE', "value": 'DOUBLE_CLICK'},
{ "active":False,
},
),
("object.swapmode",
{"type": 'MIDDLEMOUSE', "value": 'DOUBLE_CLICK'},
{ "active":False,
},
),
("wm.call_menu",
{"type": 'DEL', "value": 'PRESS', "repeat": True},
{"properties":
[("name", 'VIEW3D_MT_edit_mesh_delete'),
],
},
),
],
},
),
@@ -3014,6 +2985,11 @@ keyconfig_data = \
("anim.keyframe_insert_menu", {"type": 'I', "value": 'PRESS', "repeat": True}, None),
("anim.keyframe_delete_v3d", {"type": 'I', "value": 'PRESS', "alt": True, "repeat": True}, None),
("anim.keying_set_active_set", {"type": 'I', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True, "repeat": True}, None),
("collection.create",
{"type": 'G', "value": 'PRESS', "ctrl": True, "repeat": True},
{ "active":False,
},
),
("collection.objects_remove", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True, "repeat": True}, None),
("collection.objects_remove_all", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True, "alt": True, "repeat": True}, None),
("collection.objects_add_active", {"type": 'G', "value": 'PRESS', "shift": True, "ctrl": True, "repeat": True}, None),
@@ -3211,7 +3187,7 @@ keyconfig_data = \
],
},
),
("object.pivotlock", {"type": 'V', "value": 'PRESS', "repeat": True}, None),
("object.pivotlock", {"type": 'V', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
("object.hideorigin", {"type": 'D', "value": 'PRESS', "repeat": True}, None),
("theme.double", {"type": 'B', "value": 'PRESS', "alt": True, "repeat": True}, None),
("object.keygridsnap", {"type": 'G', "value": 'PRESS', "key_modifier": 'D', "repeat": True}, None),
@@ -3413,7 +3389,6 @@ keyconfig_data = \
("outliner.drivers_add_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
("outliner.drivers_delete_selected", {"type": 'D', "value": 'PRESS', "ctrl": True, "alt": True, "repeat": True}, None),
("outliner.collection_new", {"type": 'C', "value": 'PRESS', "repeat": True}, None),
("outliner.collection_delete", {"type": 'X', "value": 'PRESS', "repeat": True}, None),
("outliner.delete", {"type": 'DEL', "value": 'PRESS', "repeat": True}, None),
("object.move_to_collection", {"type": 'M', "value": 'PRESS', "repeat": True}, None),
("object.link_to_collection", {"type": 'M', "value": 'PRESS', "shift": True, "repeat": True}, None),
@@ -3528,6 +3503,7 @@ keyconfig_data = \
("outliner.show_active", {"type": 'F', "value": 'PRESS', "repeat": True}, None),
("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("object.move_to_collection", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("outliner.delete", {"type": 'X', "value": 'PRESS'}, None),
],
},
),
@@ -4306,6 +4282,7 @@ keyconfig_data = \
{"properties":
[("extend", False),
],
"active":False,
},
),
("uv.select",
@@ -4503,14 +4480,13 @@ keyconfig_data = \
},
),
("wm.call_menu",
{"type": 'E', "value": 'PRESS', "repeat": True},
{"type": 'RIGHTMOUSE', "value": 'PRESS'},
{"properties":
[("name", 'IMAGE_MT_uvs_specials'),
[("name", 'IMAGE_MT_uvs_context_menu'),
],
"active":False,
},
),
("uv.cursor_set", {"type": 'LEFTMOUSE', "value": 'CLICK'}, None),
("uv.cursor_set", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True}, None),
("wm.tool_set_by_name", {"type": 'Q', "value": 'PRESS', "repeat": True}, None),
("wm.tool_set_by_name", {"type": 'W', "value": 'PRESS', "repeat": True}, None),
("wm.tool_set_by_id",
@@ -4541,6 +4517,7 @@ keyconfig_data = \
],
},
),
("uv.select", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
],
},
),
@@ -4595,6 +4572,24 @@ keyconfig_data = \
("ui.list_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("ui.view_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("anim.keyframe_insert_by_name", {"type": 'S', "value": 'PRESS'}, None),
("ui.view_item_select", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("ui.view_item_select",
{"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties":
[("extend", True),
],
},
),
("ui.view_item_select",
{"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties":
[("range_select", True),
],
},
),
("ui.view_scroll", {"type": 'WHEELUPMOUSE', "value": 'ANY'}, None),
("ui.view_scroll", {"type": 'WHEELDOWNMOUSE', "value": 'ANY'}, None),
("ui.view_scroll", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
],
},
),
@@ -4603,12 +4598,7 @@ keyconfig_data = \
{"items":
[("view2d.scroller_activate", {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
("view2d.scroller_activate", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
("view2d.pan",
{"type": 'MIDDLEMOUSE', "value": 'PRESS', "shift": True},
{ "active":False,
},
),
("view2d.pan", {"type": 'TRACKPADPAN', "value": 'ANY'}, None),
("view2d.pan", {"type": 'MIDDLEMOUSE', "value": 'PRESS'}, None),
("view2d.scroll_right", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "ctrl": True}, None),
("view2d.scroll_left", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "ctrl": True}, None),
("view2d.scroll_down", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
@@ -4670,8 +4660,8 @@ keyconfig_data = \
{"type": 'F', "value": 'PRESS', "repeat": True},
{"properties":
[("data_path_primary", 'tool_settings.weight_paint.brush.size'),
("data_path_secondary", 'tool_settings.unified_paint_settings.size'),
("use_secondary", 'tool_settings.unified_paint_settings.use_unified_size'),
("data_path_secondary", 'tool_settings.weight_paint.unified_paint_settings.size'),
("use_secondary", 'tool_settings.weight_paint.unified_paint_settings.use_unified_size'),
("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'),
("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'),
("fill_color_path", ''),
@@ -4687,8 +4677,8 @@ keyconfig_data = \
{"type": 'F', "value": 'PRESS', "shift": True, "repeat": True},
{"properties":
[("data_path_primary", 'tool_settings.weight_paint.brush.strength'),
("data_path_secondary", 'tool_settings.unified_paint_settings.strength'),
("use_secondary", 'tool_settings.unified_paint_settings.use_unified_strength'),
("data_path_secondary", 'tool_settings.weight_paint.unified_paint_settings.strength'),
("use_secondary", 'tool_settings.weight_paint.unified_paint_settings.use_unified_strength'),
("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'),
("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'),
("fill_color_path", ''),
@@ -4704,8 +4694,8 @@ keyconfig_data = \
{"type": 'F', "value": 'PRESS', "ctrl": True, "repeat": True},
{"properties":
[("data_path_primary", 'tool_settings.weight_paint.brush.weight'),
("data_path_secondary", 'tool_settings.unified_paint_settings.weight'),
("use_secondary", 'tool_settings.unified_paint_settings.use_unified_weight'),
("data_path_secondary", 'tool_settings.weight_paint.unified_paint_settings.weight'),
("use_secondary", 'tool_settings.weight_paint.unified_paint_settings.use_unified_weight'),
("rotation_path", 'tool_settings.weight_paint.brush.texture_slot.angle'),
("color_path", 'tool_settings.weight_paint.brush.cursor_color_add'),
("fill_color_path", ''),