Brushstroke Tools: Initial Version #328

Merged
Simon Thommes merged 229 commits from SimonThommes/blender-studio-tools:brushstroke_tools-initial-version into main 2024-11-06 15:03:47 +01:00
3 changed files with 83 additions and 4 deletions
Showing only changes of commit 7378e61cbe - Show all commits

View File

@ -46,6 +46,8 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
# attach surface object pointer # attach surface object pointer
brushstrokes_object['BSBST_surface_object'] = surface_object brushstrokes_object['BSBST_surface_object'] = surface_object
brushstrokes_object['BSBST_active'] = True
brushstrokes_object['BSBST_method'] = settings.brushstroke_method
if surface_object: if surface_object:
surface_object.add_rest_position_attribute = True # TODO report if library data surface_object.add_rest_position_attribute = True # TODO report if library data

View File

@ -1,4 +1,39 @@
import bpy import bpy
from bpy.app.handlers import persistent
@persistent
def find_context_brushstrokes(dummy):
context = bpy.context
settings = context.scene.BSBST_settings
# identify context brushstrokes
for el in range(len(settings.context_brushstrokes)):
settings.context_brushstrokes.remove(0)
context_object = context.object
if 'BSBST_surface_object' in context_object.keys():
ob = context_object['BSBST_surface_object']
if ob:
context_object = ob
for ob in bpy.data.objects:
if not ('BSBST_surface_object' in ob.keys()):
continue
if not ob['BSBST_surface_object']:
continue
if not ob['BSBST_surface_object'] == context_object:
continue
bs = settings.context_brushstrokes.add()
bs.name = ob.name
bs.method = ob['BSBST_method']
settings.active_context_brushstrokes_index = max(min(settings.active_context_brushstrokes_index, len(settings.context_brushstrokes)-1), 0)
return
def update_active_brushstrokes(self, context):
settings = context.scene.BSBST_settings
for i, el in enumerate(settings.context_brushstrokes):
ob = bpy.data.objects.get(el.name)
if not ob:
continue
ob['BSBST_active'] = i == settings.active_context_brushstrokes_index
return
def update_brushstroke_method(self, context): def update_brushstroke_method(self, context):
SimonThommes marked this conversation as resolved Outdated

Generally, the code would be easier to read if line lengths were more limited. E.g. for Blender we have a 120 line length limit. That also makes it easier to have two files open next to each other. Such limits can be enforced automatically with auto-formatters like autopep8 (what we currently use in Blender) or e.g. black.

Generally, the code would be easier to read if line lengths were more limited. E.g. for Blender we have a 120 line length limit. That also makes it easier to have two files open next to each other. Such limits can be enforced automatically with auto-formatters like `autopep8` (what we currently use in Blender) or e.g. `black`.
settings = context.scene.BSBST_settings settings = context.scene.BSBST_settings
@ -14,6 +49,10 @@ class BSBST_socket_info(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default='') name: bpy.props.StringProperty(default='')
socket_info: bpy.props.CollectionProperty(type=BSBST_link_context_setting) socket_info: bpy.props.CollectionProperty(type=BSBST_link_context_setting)
class BSBST_context_brushstrokes(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default='')
method: bpy.props.StringProperty(default='')
class BSBST_Settings(bpy.types.PropertyGroup): class BSBST_Settings(bpy.types.PropertyGroup):
attach_to_active_selection: bpy.props.BoolProperty(default=True) attach_to_active_selection: bpy.props.BoolProperty(default=True)
preset_object: bpy.props.PointerProperty(type=bpy.types.Object, name="Preset Object") preset_object: bpy.props.PointerProperty(type=bpy.types.Object, name="Preset Object")
@ -42,11 +81,13 @@ class BSBST_Settings(bpy.types.PropertyGroup):
[('CURVE', 'Legacy', 'Use legacy curve type (Limited Support)', 'CURVE_DATA', 0),\ [('CURVE', 'Legacy', 'Use legacy curve type (Limited Support)', 'CURVE_DATA', 0),\
('CURVES', 'Curves', 'Use hair curves (Full Support)', 'CURVES_DATA', 1), ('CURVES', 'Curves', 'Use hair curves (Full Support)', 'CURVES_DATA', 1),
]) ])
#preset_mode context_brushstrokes: bpy.props.CollectionProperty(type=BSBST_context_brushstrokes)
active_context_brushstrokes_index: bpy.props.IntProperty(default = 0, update=update_active_brushstrokes)
classes = [ classes = [
BSBST_link_context_setting, BSBST_link_context_setting,
BSBST_socket_info, BSBST_socket_info,
BSBST_context_brushstrokes,
BSBST_Settings, BSBST_Settings,
] ]
@ -56,6 +97,8 @@ def register():
bpy.types.Scene.BSBST_settings = bpy.props.PointerProperty(type=BSBST_Settings) bpy.types.Scene.BSBST_settings = bpy.props.PointerProperty(type=BSBST_Settings)
bpy.types.Object.modifier_info = bpy.props.CollectionProperty(type=BSBST_socket_info) bpy.types.Object.modifier_info = bpy.props.CollectionProperty(type=BSBST_socket_info)
bpy.app.handlers.depsgraph_update_post.append(find_context_brushstrokes)
def unregister(): def unregister():
for c in classes: for c in classes:
bpy.utils.unregister_class(c) bpy.utils.unregister_class(c)

View File

@ -53,6 +53,26 @@ def draw_panel_ui_recursive(panel, panel_name, mod, items):
row.prop(s, 'link_context', text='', icon=icon) row.prop(s, 'link_context', text='', icon=icon)
return return
class BSBST_UL_brushstroke_objects(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
settings = data
context_brushstroke = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if context_brushstroke:
method_icon = 'BRUSH_DATA'
if context_brushstroke.method == 'SURFACE_FILL':
method_icon = 'OUTLINER_OB_FORCE_FIELD'
elif context_brushstroke.method == 'SURFACE_DRAW':
method_icon = 'OUTLINER_DATA_GP_LAYER'
layout.label(text=context_brushstroke.name, icon=method_icon)
else:
layout.label(text="", translate=False, icon_value=icon)
elif self.layout_type == 'GRID':
layout.label(text="", icon_value=icon)
def draw_filter(self, context, layout):
return
class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel): class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' bl_region_type = 'UI'
@ -88,10 +108,17 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
# identify style context # identify style context
style_object = context.object if settings.style_context=='BRUSHSTROKES' else settings.preset_object style_object = context.object if settings.style_context=='BRUSHSTROKES' else settings.preset_object
if settings.style_context=='PRESET':
if context.object and settings.style_context=='AUTO': style_object = settings.preset_object
if 'BSBST_surface_object' in context.object.keys(): else:
if 'BSBST_active' in context.object.keys():
style_object = context.object style_object = context.object
else:
if settings.context_brushstrokes:
bs_name = settings.context_brushstrokes[settings.active_context_brushstrokes_index].name
context_bs = bpy.data.objects.get(bs_name)
if context_bs:
style_object = context_bs
is_preset = style_object == settings.preset_object is_preset = style_object == settings.preset_object
@ -105,6 +132,12 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
style_header.row().prop(settings, 'style_context', icon_only=True, expand=True) style_header.row().prop(settings, 'style_context', icon_only=True, expand=True)
if style_panel: if style_panel:
if settings.style_context=='BRUSHSTROKES' and not 'BSBST_active' in style_object.keys():
style_panel.label(text='No Brushstroke Context Found', icon='ERROR')
return
if not is_preset and len(settings.context_brushstrokes)>0:
style_panel.template_list("BSBST_UL_brushstroke_objects", "", settings, "context_brushstrokes",
settings, "active_context_brushstrokes_index", rows=1, maxrows=5, sort_lock=True)
style_panel.prop(settings, 'preset_material', icon='MATERIAL') style_panel.prop(settings, 'preset_material', icon='MATERIAL')
if not settings.preset_object: if not settings.preset_object:
style_panel.operator("brushstroke_tools.init_preset", icon='MODIFIER') style_panel.operator("brushstroke_tools.init_preset", icon='MODIFIER')
@ -143,6 +176,7 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
return return
classes = [ classes = [
BSBST_UL_brushstroke_objects,
BSBST_PT_brushstroke_tools_panel, BSBST_PT_brushstroke_tools_panel,
] ]