2026-03-16
This commit is contained in:
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
@@ -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'}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user