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
4 changed files with 51 additions and 28 deletions
Showing only changes of commit 0e32f44f19 - Show all commits

View File

@ -112,10 +112,16 @@ class BSBST_OT_new_brushstrokes(bpy.types.Operator):
continue continue
if not settings.preset_object.modifier_info[mod.name].socket_info[v.identifier].link_context: if not settings.preset_object.modifier_info[mod.name].socket_info[v.identifier].link_context:
continue continue
if type(v) == bpy.types.NodeTreeInterfaceSocketObject: # initialize linked context parameters
link_context_type = settings.preset_object.modifier_info[mod.name].socket_info[v.identifier].link_context_type
if link_context_type=='SURFACE_OBJECT':
brushstrokes_object.modifiers[mod.name][f'{v.identifier}'] = surface_object brushstrokes_object.modifiers[mod.name][f'{v.identifier}'] = surface_object
elif type(v) == bpy.types.NodeTreeInterfaceSocketMaterial: elif link_context_type=='FLOW_OBJECT':
brushstrokes_object.modifiers[mod.name][f'{v.identifier}'] = flow_object
elif link_context_type=='MATERIAL':
brushstrokes_object.modifiers[mod.name][f'{v.identifier}'] = settings.preset_material brushstrokes_object.modifiers[mod.name][f'{v.identifier}'] = settings.preset_material
elif link_context_type=='UVMAP':
brushstrokes_object.modifiers[mod.name][f'{v.identifier}_attribute_name'] = surface_object.data.uv_layers.active.name
# refresh UI # refresh UI
for mod in brushstrokes_object.modifiers: for mod in brushstrokes_object.modifiers:
mod.node_group.interface_update(context) mod.node_group.interface_update(context)
@ -180,13 +186,9 @@ class BSBST_OT_init_preset(bpy.types.Operator):
if not mod_info: if not mod_info:
mod_info = settings.preset_object.modifier_info.add() mod_info = settings.preset_object.modifier_info.add()
mod_info.name = mod.name mod_info.name = mod.name
socket_info = mod_info.socket_info.get('Socket_2') utils.mark_socket_context_type(mod_info, 'Socket_2', 'SURFACE_OBJECT')
if not socket_info:
socket_info = mod_info.socket_info.add()
socket_info.name = 'Socket_2'
socket_info.link_context = True
## brushstrokes ## brushstrokes
mod = preset_object.modifiers.new('Brushstrokes', 'NODES') mod = preset_object.modifiers.new('Brushstrokes', 'NODES')
mod.node_group = bpy.data.node_groups['.brushstroke_tools.surface_fill'] mod.node_group = bpy.data.node_groups['.brushstroke_tools.surface_fill']
@ -195,6 +197,9 @@ class BSBST_OT_init_preset(bpy.types.Operator):
if not mod_info: if not mod_info:
mod_info = settings.preset_object.modifier_info.add() mod_info = settings.preset_object.modifier_info.add()
mod_info.name = mod.name mod_info.name = mod.name
utils.mark_socket_context_type(mod_info, 'Socket_2', 'FLOW_OBJECT')
utils.mark_socket_context_type(mod_info, 'Socket_3', 'UVMAP')
return return
SimonThommes marked this conversation as resolved Outdated

It's not really necessary to have empty return statements.

It's not really necessary to have empty return statements.
@ -212,12 +217,8 @@ class BSBST_OT_init_preset(bpy.types.Operator):
if not mod_info: if not mod_info:
mod_info = settings.preset_object.modifier_info.add() mod_info = settings.preset_object.modifier_info.add()
mod_info.name = mod.name mod_info.name = mod.name
socket_info = mod_info.socket_info.get('Socket_2') utils.mark_socket_context_type(mod_info, 'Socket_2', 'SURFACE_OBJECT')
if not socket_info:
socket_info = mod_info.socket_info.add()
socket_info.name = 'Socket_2'
socket_info.link_context = True
## brushstrokes ## brushstrokes
mod = preset_object.modifiers.new('Brushstrokes', 'NODES') mod = preset_object.modifiers.new('Brushstrokes', 'NODES')
@ -227,12 +228,8 @@ class BSBST_OT_init_preset(bpy.types.Operator):
if not mod_info: if not mod_info:
mod_info = settings.preset_object.modifier_info.add() mod_info = settings.preset_object.modifier_info.add()
mod_info.name = mod.name mod_info.name = mod.name
socket_info = mod_info.socket_info.get('Socket_2') utils.mark_socket_context_type(mod_info, 'Socket_2', 'SURFACE_OBJECT')
if not socket_info:
socket_info = mod_info.socket_info.add()
socket_info.name = 'Socket_2'
socket_info.link_context = True
return return

View File

@ -54,6 +54,10 @@ def update_brushstroke_method(self, context):
settings.preset_object = preset_object settings.preset_object = preset_object
return return
def update_link_context_type(self, context):
self.link_context = True
return
def get_brushstroke_name(self): def get_brushstroke_name(self):
return self["name"] return self["name"]
@ -77,7 +81,13 @@ def set_brushstroke_name(self, value):
class BSBST_link_context_setting(bpy.types.PropertyGroup): class BSBST_link_context_setting(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default='') name: bpy.props.StringProperty(default='')
link_context: bpy.props.BoolProperty(default=False) link_context: bpy.props.BoolProperty(default=False, name='Link to Context')
link_context_type: bpy.props.EnumProperty(default='SURFACE_OBJECT', name='Link to Context', update=update_link_context_type,
items= [('SURFACE_OBJECT', 'Surface Object', 'Link socket preset to context surface object', 'OUTLINER_OB_SURFACE', 1),\
('FLOW_OBJECT', 'Flow Object', 'Link socket preset to context flow object', 'FORCE_WIND', 11),
('MATERIAL', 'Material', 'Link socket preset to context material', 'MATERIAL', 101),
('UVMAP', 'UV Map', 'Link socket preset to active context UVMap', 'UV', 201),
])
class BSBST_socket_info(bpy.types.PropertyGroup): class BSBST_socket_info(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default='') name: bpy.props.StringProperty(default='')

View File

@ -26,11 +26,13 @@ def draw_panel_ui_recursive(panel, panel_name, mod, items):
continue continue
if f'{v.identifier}' not in mod.keys(): if f'{v.identifier}' not in mod.keys():
continue continue
row = panel.row() row = panel.row(align=True)
col = row.column() col = row.column()
input_row = col.row(align=True) input_row = col.row(align=True)
attribute_toggle = False
if f'{v.identifier}_use_attribute' in mod.keys(): if f'{v.identifier}_use_attribute' in mod.keys():
if mod[f'{v.identifier}_use_attribute']: attribute_toggle = mod[f'{v.identifier}_use_attribute']
if attribute_toggle:
input_row.prop(mod, f'["{v.identifier}_attribute_name"]', text=k) input_row.prop(mod, f'["{v.identifier}_attribute_name"]', text=k)
else: else:
input_row.prop(mod, f'["{v.identifier}"]', text=k) input_row.prop(mod, f'["{v.identifier}"]', text=k)
@ -44,13 +46,19 @@ def draw_panel_ui_recursive(panel, panel_name, mod, items):
input_row.prop(mod, f'["{v.identifier}"]', text=k) input_row.prop(mod, f'["{v.identifier}"]', text=k)
if not mod_info: if not mod_info:
continue continue
if type(v) in utils.linkable_sockets: if type(v) in utils.linkable_sockets and (attribute_toggle or not f'{v.identifier}_use_attribute' in mod.keys()):
s = mod_info.socket_info.get(v.identifier) s = mod_info.socket_info.get(v.identifier)
if not s:
continue
col.enabled = not s.link_context col.enabled = not s.link_context
if not s: if not s:
continue continue
icon = link_icon_dict[type(v)] if type(v) in link_icon_dict.keys() else 'LINKED' icon = s.bl_rna.properties['link_context_type'].enum_items[s.link_context_type].icon
row.prop(s, 'link_context', text='', icon=icon) row.alignment = 'EXPAND'
if s.link_context:
row.prop(s, 'link_context', text='', icon=icon)
else:
row.prop(s, 'link_context_type', text='', emboss=True, icon='LINKED', icon_only=True)
return return
class BSBST_UL_brushstroke_objects(bpy.types.UIList): class BSBST_UL_brushstroke_objects(bpy.types.UIList):

View File

@ -9,7 +9,7 @@ ng_list = [ ".brushstroke_tools.processing",
".brushstroke_tools.geometry_input", ".brushstroke_tools.geometry_input",
] ]
linkable_sockets = [bpy.types.NodeTreeInterfaceSocketObject, bpy.types.NodeTreeInterfaceSocketMaterial] linkable_sockets = [bpy.types.NodeTreeInterfaceSocketObject, bpy.types.NodeTreeInterfaceSocketMaterial, bpy.types.NodeTreeInterfaceSocketVector]
@persistent @persistent
def refresh_preset(dummy): def refresh_preset(dummy):
@ -37,6 +37,14 @@ def refresh_preset(dummy):
# TODO: clean up old settings # TODO: clean up old settings
return return
def mark_socket_context_type(mod_info, socket_name, link_type):
socket_info = mod_info.socket_info.get(socket_name)
if not socket_info:
socket_info = mod_info.socket_info.add()
socket_info.name = socket_name
socket_info.link_context_type = link_type
return
def get_addon_directory() -> str: def get_addon_directory() -> str:
""" """
Returns the path of the addon directory to be used to append resource data-blocks. Returns the path of the addon directory to be used to append resource data-blocks.