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):
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,
] ]