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
brushstrokes_object['BSBST_surface_object'] = surface_object
brushstrokes_object['BSBST_active'] = True
brushstrokes_object['BSBST_method'] = settings.brushstroke_method
if surface_object:
surface_object.add_rest_position_attribute = True # TODO report if library data

View File

@ -1,4 +1,39 @@
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):
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
@ -14,6 +49,10 @@ class BSBST_socket_info(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default='')
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):
attach_to_active_selection: bpy.props.BoolProperty(default=True)
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),\
('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 = [
BSBST_link_context_setting,
BSBST_socket_info,
BSBST_context_brushstrokes,
BSBST_Settings,
]
@ -56,6 +97,8 @@ def register():
bpy.types.Scene.BSBST_settings = bpy.props.PointerProperty(type=BSBST_Settings)
bpy.types.Object.modifier_info = bpy.props.CollectionProperty(type=BSBST_socket_info)
bpy.app.handlers.depsgraph_update_post.append(find_context_brushstrokes)
def unregister():
for c in classes:
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)
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):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@ -88,10 +108,17 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
# identify style context
style_object = context.object if settings.style_context=='BRUSHSTROKES' else settings.preset_object
if context.object and settings.style_context=='AUTO':
if 'BSBST_surface_object' in context.object.keys():
if settings.style_context=='PRESET':
style_object = settings.preset_object
else:
if 'BSBST_active' in context.object.keys():
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
@ -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)
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')
if not settings.preset_object:
style_panel.operator("brushstroke_tools.init_preset", icon='MODIFIER')
@ -143,6 +176,7 @@ class BSBST_PT_brushstroke_tools_panel(bpy.types.Panel):
return
classes = [
BSBST_UL_brushstroke_objects,
BSBST_PT_brushstroke_tools_panel,
]