Sculpt: experimental brush palette ui
Pure python, experimental.
This commit is contained in:
parent
f52ed67289
commit
e01dd8140e
|
@ -69,6 +69,8 @@ _modules = [
|
|||
"properties_world",
|
||||
"properties_collection",
|
||||
|
||||
"sculpt_ui",
|
||||
|
||||
# Generic Space Modules
|
||||
#
|
||||
# Depends on DNA_WORKSPACE_TOOL (C define).
|
||||
|
@ -125,6 +127,9 @@ def register():
|
|||
WindowManager,
|
||||
)
|
||||
|
||||
from . import sculpt_ui
|
||||
sculpt_ui.post_register()
|
||||
|
||||
# space_userprefs.py
|
||||
def addon_filter_items(_self, _context):
|
||||
import addon_utils
|
||||
|
|
|
@ -337,6 +337,9 @@ class UnifiedPaintPanel:
|
|||
""" Generalized way of adding brush options to the UI,
|
||||
along with their pen pressure setting and global toggle"""
|
||||
|
||||
if slider is None:
|
||||
slider = False
|
||||
|
||||
if ui_editing is None:
|
||||
ui_editing = True
|
||||
ui_editing = ui_editing and not header
|
||||
|
@ -1243,7 +1246,6 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
brush,
|
||||
"dyntopo_disabled",
|
||||
#text="Weight By Face Area",
|
||||
slider=True,
|
||||
header=True
|
||||
)
|
||||
#layout.prop(brush.dyntopo, "disabled", text="Disable Dyntopo")
|
||||
|
@ -1257,7 +1259,16 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
text = "Pinch"
|
||||
if sculpt_tool in {'BLOB', 'SNAKE_HOOK'}:
|
||||
text = "Magnify"
|
||||
layout.prop(brush, "crease_pinch_factor", slider=True, text=text)
|
||||
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"crease_pinch_factor",
|
||||
#text="Weight By Face Area",
|
||||
slider=True,
|
||||
text = text
|
||||
)
|
||||
|
||||
# rake_factor
|
||||
if capabilities.has_rake_factor:
|
||||
|
@ -1310,7 +1321,7 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
layout.prop(brush, "height", slider=True, text="Height")
|
||||
|
||||
# use_persistent, set_persistent_base
|
||||
if capabilities.has_persistence:
|
||||
if 0: #capabilities.has_persistence:
|
||||
layout.separator()
|
||||
layout.prop(brush, "use_persistent")
|
||||
layout.operator("sculpt.set_persistent_base")
|
||||
|
@ -1335,89 +1346,211 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
|
||||
# Per sculpt tool options.
|
||||
|
||||
def doprop(col, prop, slider=None):
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
col,
|
||||
context,
|
||||
brush,
|
||||
prop,
|
||||
slider=slider
|
||||
)
|
||||
|
||||
if sculpt_tool == "VCOL_BOUNDARY":
|
||||
row = layout.row()
|
||||
row.prop(brush, "vcol_boundary_exponent")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
row,
|
||||
context,
|
||||
brush,
|
||||
"vcol_boundary_exponent",
|
||||
slider=True
|
||||
)
|
||||
|
||||
if sculpt_tool == 'CLAY_STRIPS':
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_roundness")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
row,
|
||||
context,
|
||||
brush,
|
||||
"tip_roundness",
|
||||
slider=True
|
||||
)
|
||||
|
||||
elif sculpt_tool == 'ELASTIC_DEFORM':
|
||||
layout.separator()
|
||||
layout.prop(brush, "elastic_deform_type")
|
||||
layout.prop(brush, "elastic_deform_volume_preservation", slider=True)
|
||||
layout.prop(brush, "use_surface_falloff")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"elastic_deform_type",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"elastic_deform_volume_preservation",
|
||||
slider=True
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"use_surface_falloff",
|
||||
)
|
||||
layout.separator()
|
||||
|
||||
elif sculpt_tool == 'SNAKE_HOOK':
|
||||
layout.separator()
|
||||
layout.prop(brush, "snake_hook_deform_type")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"snake_hook_deform_type",
|
||||
)
|
||||
layout.separator()
|
||||
|
||||
elif sculpt_tool == 'POSE':
|
||||
layout.separator()
|
||||
layout.prop(brush, "deform_target")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"deform_target",
|
||||
)
|
||||
layout.separator()
|
||||
layout.prop(brush, "pose_deform_type")
|
||||
layout.prop(brush, "pose_origin_type")
|
||||
layout.prop(brush, "pose_offset")
|
||||
layout.prop(brush, "pose_smooth_iterations")
|
||||
if brush.pose_deform_type == 'ROTATE_TWIST' and brush.pose_origin_type in {'TOPOLOGY', 'FACE_SETS'}:
|
||||
layout.prop(brush, "pose_ik_segments")
|
||||
if brush.pose_deform_type == 'SCALE_TRANSLATE':
|
||||
layout.prop(brush, "use_pose_lock_rotation")
|
||||
layout.prop(brush, "use_pose_ik_anchored")
|
||||
layout.prop(brush, "use_connected_only")
|
||||
layout.prop(brush, "disconnected_distance_max")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"pose_deform_type",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"pose_origin_type",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"pose_offset",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"pose_smooth_iterations",
|
||||
)
|
||||
|
||||
if brush.channels["pose_deform_type"].value == 'ROTATE_TWIST' and \
|
||||
brush.channels["pose_origin_type"].value in {'TOPOLOGY', 'FACE_SETS'}:
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"pose_ik_segments",
|
||||
)
|
||||
if brush.channels["pose_deform_type"].value == 'SCALE_TRANSLATE':
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"use_pose_lock_rotation",
|
||||
)
|
||||
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"use_pose_ik_anchored",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"use_connected_only",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"disconnected_distance_max",
|
||||
)
|
||||
|
||||
layout.separator()
|
||||
|
||||
elif sculpt_tool == 'CLOTH':
|
||||
layout.separator()
|
||||
layout.prop(brush, "cloth_simulation_area_type")
|
||||
if brush.cloth_simulation_area_type != 'GLOBAL':
|
||||
layout.prop(brush, "cloth_sim_limit")
|
||||
layout.prop(brush, "cloth_sim_falloff")
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"cloth_simulation_area_type",
|
||||
)
|
||||
|
||||
if brush.cloth_simulation_area_type == 'LOCAL':
|
||||
layout.prop(brush, "use_cloth_pin_simulation_boundary")
|
||||
if brush.channels["cloth_simulation_area_type"].value != 'GLOBAL':
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"cloth_sim_limit",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"cloth_sim_falloff",
|
||||
)
|
||||
|
||||
if brush.channels["cloth_simulation_area_type"].value == 'LOCAL':
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"cloth_sim_falloff",
|
||||
)
|
||||
UnifiedPaintPanel.channel_unified(
|
||||
layout,
|
||||
context,
|
||||
brush,
|
||||
"cloth_pin_simulation_boundary",
|
||||
)
|
||||
|
||||
layout.separator()
|
||||
layout.prop(brush, "cloth_deform_type")
|
||||
layout.prop(brush, "cloth_force_falloff_type")
|
||||
doprop(layout, "cloth_deform_type")
|
||||
doprop(layout, "cloth_force_falloff_type")
|
||||
layout.separator()
|
||||
layout.prop(brush, "cloth_mass")
|
||||
layout.prop(brush, "cloth_damping")
|
||||
layout.prop(brush, "cloth_constraint_softbody_strength")
|
||||
doprop(layout, "cloth_mass")
|
||||
doprop(layout, "cloth_damping")
|
||||
doprop(layout, "cloth_constraint_softbody_strength")
|
||||
layout.separator()
|
||||
layout.prop(brush, "use_cloth_collision")
|
||||
doprop(layout, "use_cloth_collision")
|
||||
layout.separator()
|
||||
|
||||
elif sculpt_tool == 'SCRAPE':
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "area_radius_factor")
|
||||
row.prop(brush, "use_pressure_area_radius", text="")
|
||||
doprop(row, "area_radius_factor")
|
||||
doprop(row, "use_pressure_area_radius", text="")
|
||||
row = layout.row()
|
||||
row.prop(brush, "invert_to_scrape_fill", text="Invert to Fill")
|
||||
doprop(row, "invert_to_scrape_fill", text="Invert to Fill")
|
||||
|
||||
elif sculpt_tool == 'FILL':
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "area_radius_factor")
|
||||
row.prop(brush, "use_pressure_area_radius", text="")
|
||||
doprop(row, "area_radius_factor")
|
||||
doprop(row, "use_pressure_area_radius", text="")
|
||||
row = layout.row()
|
||||
row.prop(brush, "invert_to_scrape_fill", text="Invert to Scrape")
|
||||
doprop(row, "invert_to_scrape_fill", text="Invert to Scrape")
|
||||
|
||||
elif sculpt_tool == 'GRAB':
|
||||
layout.prop(brush, "use_grab_active_vertex")
|
||||
layout.prop(brush, "use_grab_silhouette")
|
||||
layout.prop(brush, "use_surface_falloff")
|
||||
doprop(layout, "use_grab_active_vertex")
|
||||
doprop(layout, "grab_silhouette")
|
||||
doprop(layout, "use_surface_falloff")
|
||||
|
||||
elif sculpt_tool == 'PAINT':
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "flow")
|
||||
row.prop(brush, "invert_flow_pressure", text="")
|
||||
row.prop(brush, "use_flow_pressure", text="")
|
||||
doprop(row, "flow")
|
||||
doprop(row, "invert_flow_pressure", text="")
|
||||
doprop(row, "use_flow_pressure", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "wet_mix")
|
||||
|
@ -1425,56 +1558,56 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
row.prop(brush, "use_wet_mix_pressure", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "wet_persistence")
|
||||
row.prop(brush, "invert_wet_persistence_pressure", text="")
|
||||
row.prop(brush, "use_wet_persistence_pressure", text="")
|
||||
doprop(row, "wet_persistence")
|
||||
doprop(row, "invert_wet_persistence_pressure", text="")
|
||||
doprop(row, "use_wet_persistence_pressure", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "wet_paint_radius_factor")
|
||||
doprop(row, "wet_paint_radius_factor")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(brush, "density")
|
||||
row.prop(brush, "invert_density_pressure", text="")
|
||||
row.prop(brush, "use_density_pressure", text="")
|
||||
doprop(row, "density")
|
||||
doprop(row, "invert_density_pressure", text="")
|
||||
doprop(row, "use_density_pressure", text="")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_roundness")
|
||||
doprop(row, "tip_roundness")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(brush, "tip_scale_x")
|
||||
doprop(row, "tip_scale_x")
|
||||
|
||||
elif sculpt_tool == 'SMEAR':
|
||||
col = layout.column()
|
||||
col.prop(brush, "smear_deform_type")
|
||||
doprop(col, "smear_deform_type")
|
||||
|
||||
elif sculpt_tool == 'BOUNDARY':
|
||||
layout.prop(brush, "deform_target")
|
||||
doprop(layout, "deform_target")
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.prop(brush, "boundary_deform_type")
|
||||
col.prop(brush, "boundary_falloff_type")
|
||||
col.prop(brush, "boundary_offset")
|
||||
doprop(col, "boundary_deform_type")
|
||||
doprop(col, "boundary_falloff_type")
|
||||
doprop(col, "boundary_offset")
|
||||
|
||||
elif sculpt_tool == 'TOPOLOGY':
|
||||
col = layout.column()
|
||||
col.prop(brush, "slide_deform_type")
|
||||
doprop(col, "slide_deform_type")
|
||||
|
||||
elif sculpt_tool == 'MULTIPLANE_SCRAPE':
|
||||
col = layout.column()
|
||||
col.prop(brush, "multiplane_scrape_angle")
|
||||
col.prop(brush, "use_multiplane_scrape_dynamic")
|
||||
col.prop(brush, "show_multiplane_scrape_planes_preview")
|
||||
doprop(col, "multiplane_scrape_angle")
|
||||
doprop(col, "use_multiplane_scrape_dynamic")
|
||||
doprop(col, "show_multiplane_scrape_planes_preview")
|
||||
|
||||
elif sculpt_tool == 'SCENE_PROJECT':
|
||||
col = layout.column()
|
||||
col.prop(brush, "scene_project_direction_type")
|
||||
doprop(col, "scene_project_direction_type")
|
||||
|
||||
elif sculpt_tool == 'ARRAY':
|
||||
col = layout.column()
|
||||
col.prop(brush, "array_deform_type")
|
||||
col.prop(brush, "array_count")
|
||||
col.prop(brush, "use_array_lock_orientation")
|
||||
col.prop(brush, "use_array_fill_holes")
|
||||
doprop(col, "array_deform_type")
|
||||
doprop(col, "array_count")
|
||||
doprop(col, "use_array_lock_orientation")
|
||||
doprop(col, "use_array_fill_holes")
|
||||
|
||||
elif sculpt_tool == 'SMOOTH':
|
||||
col = layout.column()
|
||||
|
@ -1512,19 +1645,19 @@ def brush_settings(layout, context, brush, popover=False):
|
|||
"fset_slide"
|
||||
)
|
||||
|
||||
col.prop(brush, "smooth_deform_type")
|
||||
doprop(col, "smooth_deform_type")
|
||||
|
||||
if brush.smooth_deform_type == 'SURFACE':
|
||||
col.prop(brush, "surface_smooth_shape_preservation")
|
||||
col.prop(brush, "surface_smooth_current_vertex")
|
||||
col.prop(brush, "surface_smooth_iterations")
|
||||
doprop(col, "surface_smooth_shape_preservation")
|
||||
doprop(col, "surface_smooth_current_vertex")
|
||||
doprop(col, "surface_smooth_iterations")
|
||||
|
||||
elif sculpt_tool == 'DISPLACEMENT_SMEAR':
|
||||
col = layout.column()
|
||||
col.prop(brush, "smear_deform_type")
|
||||
doprop(col, "smear_deform_type")
|
||||
|
||||
elif sculpt_tool == 'MASK':
|
||||
layout.row().prop(brush, "mask_tool", expand=True)
|
||||
doprop(layout.row(), "mask_tool", expand=True)
|
||||
|
||||
# End sculpt_tool interface.
|
||||
|
||||
|
@ -2270,12 +2403,3 @@ def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=Fals
|
|||
row.prop(gp_settings, "vertex_mode", text="Mode")
|
||||
|
||||
|
||||
classes += [
|
||||
VIEW3D_MT_tools_projectpaint_clone,
|
||||
ReorderBrushChannel
|
||||
]
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
|
|
@ -0,0 +1,542 @@
|
|||
import bpy
|
||||
import os
|
||||
import sys
|
||||
from bpy.props import *
|
||||
|
||||
from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
|
||||
|
||||
class WM_MT_button_context(bpy.types.Menu):
|
||||
bl_label = "Unused"
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
def getToolSlotName(brush):
|
||||
slot = brush.rna_type.properties["sculpt_tool"].enum_items
|
||||
return "builtin_brush." + slot[brush.sculpt_tool].name
|
||||
|
||||
def getToolSlotIndex(brush):
|
||||
for i, enum in enumerate(brush.rna_type.properties["sculpt_tool"].enum_items):
|
||||
if enum.identifier == brush.sculpt_tool:
|
||||
return i
|
||||
|
||||
def getPalette(autocreate=False):
|
||||
key = "SCULPT_PALETTE"
|
||||
|
||||
if key not in bpy.data.palettes:
|
||||
if autocreate:
|
||||
pal = bpy.data.palettes.new(key)
|
||||
for i in range(9):
|
||||
ref = pal.brush_palette.brushes.add()
|
||||
ref.type = "EMPTY"
|
||||
else:
|
||||
return None
|
||||
|
||||
return bpy.data.palettes[key].brush_palette
|
||||
|
||||
def menu_func(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
|
||||
if hasattr(context, "button_operator"):
|
||||
opname = context.button_operator.rna_type.identifier
|
||||
if opname == "SCULPT_OT_select_brush_tool":
|
||||
props = layout.operator("sculpt.remove_brush_tool")
|
||||
props.slot = context.button_operator.ref
|
||||
|
||||
layout.operator("sculpt.add_to_palette")
|
||||
layout.operator("sculpt.call_brush_palette")
|
||||
|
||||
#layout.operator(WM_MT_button_context_sculpt_palette.bl_idname)
|
||||
class BrushRef(bpy.types.PropertyGroup):
|
||||
type_items = [("BRUSH", "Brush","", 0),
|
||||
("TOOL", "Tool", "",1),
|
||||
("EMPTY", "Empty", "", 2)]
|
||||
|
||||
type : EnumProperty(items=type_items)
|
||||
brush : PointerProperty(type=bpy.types.Brush)
|
||||
tool : StringProperty()
|
||||
|
||||
class BrushPalette(bpy.types.PropertyGroup):
|
||||
brushes : CollectionProperty(type=BrushRef)
|
||||
|
||||
def brushCount(self):
|
||||
count = 0
|
||||
|
||||
for i, ref in enumerate(self.brushes):
|
||||
if ref.type != "EMPTY" and (ref.type == "TOOL" or (ref.type == "BRUSH" and ref.brush)):
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
def addBrush(self, brush):
|
||||
for ref in self.brushes:
|
||||
if ref.brush == brush:
|
||||
print("Brush already in palette!")
|
||||
return None
|
||||
if ref.type == "EMPTY" or (ref.type == "BRUSH" and not ref.brush):
|
||||
ref.type = "BRUSH"
|
||||
ref.brush = brush
|
||||
return ref
|
||||
|
||||
ref = self.brushes.add()
|
||||
ref.type = "BRUSH"
|
||||
ref.brush = brush
|
||||
return ref
|
||||
|
||||
class BrushPaletteSet(bpy.types.PropertyGroup):
|
||||
palettes : CollectionProperty(type=BrushPalette)
|
||||
active : IntProperty()
|
||||
|
||||
def getOrCreateActive(self):
|
||||
if len(self.palettes) == 0:
|
||||
self.palettes.add()
|
||||
|
||||
return self.palettes[self.active]
|
||||
|
||||
def getActive(self):
|
||||
if len(self.palettes) == 0:
|
||||
return None
|
||||
return self.palettes[self.active]
|
||||
|
||||
def sculpt_poll(cls, context):
|
||||
return context.mode == "SCULPT" and context.active_object
|
||||
|
||||
whitelist = ["mesh_filter", "cloth_filter", "line_project"
|
||||
"box_face_set", "box_mask", "box_hide",
|
||||
"ipmask_filter", "color_filter", "mask_by_color",
|
||||
"face_set_edit", "move", "rotate", "scale",
|
||||
"transform", "annotate"]
|
||||
|
||||
whitelist = set(map(lambda item: "builtin." + item, whitelist))
|
||||
|
||||
class AddToPalette(bpy.types.Operator):
|
||||
"Add brush/tool to palette"
|
||||
|
||||
bl_idname = "sculpt.add_to_palette"
|
||||
bl_label = "Add To Palette"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not sculpt_poll(cls, context):
|
||||
return False
|
||||
|
||||
ok = False
|
||||
|
||||
for k in ["button_pointer", "button_prop", "button_operator"]:
|
||||
if not hasattr(context, k):
|
||||
continue
|
||||
v = getattr(context, k)
|
||||
|
||||
print(v, dir(v))
|
||||
if hasattr(v, "name"):
|
||||
print(v.name)
|
||||
|
||||
if k == "button_operator":
|
||||
ok = v.name.startswith("builtin_brush") or v.name in whitelist
|
||||
break
|
||||
print("=====" + k + "=====")
|
||||
"""
|
||||
for k in dir(context):
|
||||
print(k)
|
||||
#"""
|
||||
|
||||
return ok
|
||||
|
||||
def execute(self, context):
|
||||
pal = getPalette(True)
|
||||
|
||||
ok = False
|
||||
key = None
|
||||
|
||||
for k in ["button_pointer", "button_prop", "button_operator"]:
|
||||
if not hasattr(context, k):
|
||||
continue
|
||||
v = getattr(context, k)
|
||||
|
||||
print(v, dir(v))
|
||||
if hasattr(v, "name"):
|
||||
print(v.name)
|
||||
|
||||
if k == "button_operator":
|
||||
ok = v.name.startswith("builtin_brush") or v.name in whitelist
|
||||
|
||||
if ok:
|
||||
key = v.name
|
||||
break
|
||||
|
||||
if not ok:
|
||||
return {'CANCELLED'}
|
||||
|
||||
print("found brush or tool", key)
|
||||
|
||||
if key.startswith("builtin_brush"):
|
||||
self.do_brush(context, key)
|
||||
else:
|
||||
self.do_tool(context, key)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def do_brush(self, context, key):
|
||||
key = key.split(".")
|
||||
type = key[1].upper()
|
||||
print(type)
|
||||
slots = context.tool_settings.sculpt.tool_slots
|
||||
|
||||
slot = None
|
||||
|
||||
for slot2 in slots:
|
||||
if not slot2.brush: continue
|
||||
if slot2.brush.sculpt_tool == type:
|
||||
slot = slot2
|
||||
break
|
||||
|
||||
if slot is None:
|
||||
print("error!", type)
|
||||
return
|
||||
|
||||
print("found", type)
|
||||
|
||||
pal = getPalette(True)
|
||||
pal.addBrush(slot.brush)
|
||||
|
||||
def do_tool(self, context, key):
|
||||
pass
|
||||
|
||||
class SelectBrushTool(bpy.types.Operator):
|
||||
"Select brush/tool"
|
||||
|
||||
bl_idname = "sculpt.select_brush_tool"
|
||||
bl_label = "Select Brush/Tool"
|
||||
|
||||
ref : IntProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return sculpt_poll(cls, context)
|
||||
|
||||
def execute(self, context):
|
||||
pal = getPalette(True)
|
||||
|
||||
ref = pal.brushes[self.ref]
|
||||
if ref.type == "TOOL":
|
||||
bpy.ops.wm.tool_set_by_id(name="builtin." + ref.tool)
|
||||
elif ref.type == "BRUSH":
|
||||
print("REF", ref.brush, ref.type, ref)
|
||||
if not ref.brush:
|
||||
return {'CANCELLED'}
|
||||
|
||||
tool = getToolSlotName(ref.brush)
|
||||
#bpy.ops.wm.tool_set_by_id(name=tool)
|
||||
bpy.ops.paint.brush_select(sculpt_tool=ref.brush.sculpt_tool)
|
||||
|
||||
sloti = getToolSlotIndex(ref.brush)
|
||||
slots = bpy.context.tool_settings.sculpt.tool_slots
|
||||
slots[sloti].brush = ref.brush
|
||||
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SetBrushTool(bpy.types.Operator):
|
||||
"Set brush/tool"
|
||||
|
||||
bl_idname = "sculpt.set_brush_tool"
|
||||
bl_label = "Set Palette Entry"
|
||||
|
||||
ref : IntProperty()
|
||||
slot : IntProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return sculpt_poll(cls, context)
|
||||
|
||||
def execute(self, context):
|
||||
pal = getPalette(True)
|
||||
slot = self.slot
|
||||
|
||||
while len(pal.brushes) <= slot:
|
||||
ref = pal.brushes.add()
|
||||
ref.type = "EMPTY"
|
||||
ref = pal.brushes[slot]
|
||||
|
||||
ref.type = "BRUSH"
|
||||
ref.brush = context.tool_settings.sculpt.brush
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class RemoveBrushTool(bpy.types.Operator):
|
||||
"Remove brush/tool"
|
||||
|
||||
bl_idname = "sculpt.remove_brush_tool"
|
||||
bl_label = "Remove Brush/Tool From Palette"
|
||||
|
||||
ref : IntProperty()
|
||||
slot : IntProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return sculpt_poll(cls, context)
|
||||
|
||||
def execute(self, context):
|
||||
pal = getPalette(True)
|
||||
slot = self.slot
|
||||
|
||||
pal.brushes[slot].type = "EMPTY"
|
||||
pal.brushes[slot].brush = None
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class CallBrushMenu(bpy.types.Operator):
|
||||
"Select brush/tool"
|
||||
|
||||
bl_idname = "sculpt.call_brush_palette"
|
||||
bl_label = "Open Brush Palette"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ok = context.active_object is not None
|
||||
ok = ok and context.mode == "SCULPT"
|
||||
ok = ok and context.tool_settings is not None
|
||||
ok = ok and context.tool_settings.sculpt is not None
|
||||
return ok
|
||||
|
||||
def invoke(cls, context, b):
|
||||
getPalette(True)
|
||||
bpy.ops.wm.call_panel(name="VIEW3D_PT_SculptPalette", keep_open=False)
|
||||
#bpy.ops.wm.call_menu(name="VIEW3D_MT_SculptPalette")
|
||||
|
||||
return {'CANCELLED'}
|
||||
|
||||
def execute(self, context):
|
||||
return {'CANCELLED'}
|
||||
|
||||
class VIEW3D_PT_SculptPalette(bpy.types.Panel):
|
||||
bl_label = "Sculpt Palette"
|
||||
bl_idname = "VIEW3D_PT_SculptPalette"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "WINDOW"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout #.menu_pie()#.column(align=True)
|
||||
row = layout.column(align=1)
|
||||
col = None #row.column(align=True)
|
||||
row.alignment = 'LEFT'
|
||||
|
||||
scale = 2.0
|
||||
|
||||
pal = getPalette(False)
|
||||
|
||||
if pal is None:
|
||||
print("no palettes")
|
||||
return
|
||||
|
||||
#rows and cols as identifiers became logically swapped during
|
||||
#development, unwap them
|
||||
|
||||
j = 0
|
||||
rows = min(int(len(pal.brushes) / 3) + 1, 3)
|
||||
cols = 3
|
||||
|
||||
if rows * cols == pal.brushCount():
|
||||
rows += 1
|
||||
|
||||
for i in range(cols * rows):
|
||||
if i % cols == 0:
|
||||
col = row.row(align=1)
|
||||
col.scale_x = scale
|
||||
col.scale_y = scale
|
||||
col.alignment = 'LEFT'
|
||||
|
||||
j += 1
|
||||
if j == rows:
|
||||
row = layout.column(align=1)
|
||||
j = 0
|
||||
|
||||
id = ((i + 0) % cols)
|
||||
id = ((j + 2) % cols) * cols + id
|
||||
|
||||
n = 0
|
||||
icon = 0
|
||||
if id < len(pal.brushes) and pal.brushes[id].type != "EMPTY" and pal.brushes[id].brush:
|
||||
|
||||
n = getToolSlotIndex(pal.brushes[id].brush)
|
||||
brush = pal.brushes[id].brush
|
||||
|
||||
vname = brush.sculpt_tool.lower()
|
||||
vname = "brush.sculpt." + vname
|
||||
print("ICON", vname)
|
||||
|
||||
icon = ToolSelectPanelHelper._icon_value_from_icon_handle(vname)
|
||||
|
||||
if id > 10:
|
||||
keyt = ''
|
||||
else:
|
||||
keyt = str(id)
|
||||
|
||||
keyt = ''
|
||||
|
||||
empty = id >= len(pal.brushes)
|
||||
empty = empty or pal.brushes[id].type == "EMPTY"
|
||||
empty = empty or pal.brushes[id].type == "BRUSH" and not pal.brushes[id]
|
||||
|
||||
if empty:
|
||||
icon = 9
|
||||
props = col.operator("sculpt.set_brush_tool", text='', icon_value=icon)
|
||||
props.slot = id
|
||||
else:
|
||||
props = col.operator("sculpt.select_brush_tool", text=keyt, icon_value=icon)
|
||||
props.ref = id
|
||||
|
||||
#col.label(text="")
|
||||
#col.template_icon(i, scale=1)
|
||||
"""
|
||||
preview_collections = {}
|
||||
|
||||
my_icons_dir = os.path.dirname(bpy.data.filepath)
|
||||
my_icons_path = ""
|
||||
my_icon_name = "my_icon"
|
||||
|
||||
class SubObj (dict):
|
||||
pass
|
||||
|
||||
def savedata(obj, subkeys={}, is_sub=False):
|
||||
props = obj.bl_rna.properties
|
||||
|
||||
ret = {} if not is_sub else SubObj()
|
||||
|
||||
for p in props:
|
||||
if p.is_readonly:
|
||||
continue
|
||||
if p.type in ["ENUM", "FLOAT", "INT", "BOOLEAN", "STRING"]:
|
||||
ret[p.identifier] = getattr(obj, p.identifier)
|
||||
|
||||
return ret
|
||||
|
||||
def loaddata(obj, data):
|
||||
for k in data:
|
||||
v = data[k]
|
||||
if type(v) == SubObj:
|
||||
loaddata(getattr(obj), v)
|
||||
continue
|
||||
|
||||
try:
|
||||
setattr(obj, k, v)
|
||||
except:
|
||||
print("failed to set property", k, "on", obj);
|
||||
|
||||
def pushRender():
|
||||
render = bpy.context.scene.render
|
||||
return savedata(render)
|
||||
|
||||
def popRender(state):
|
||||
render = bpy.context.scene.render
|
||||
loaddata(render, state)
|
||||
|
||||
state = pushRender()
|
||||
popRender(state)
|
||||
|
||||
class RenderPreview (bpy.types.Operator):
|
||||
"Render preview icon"
|
||||
|
||||
bl_idname = "render.my_render_preview"
|
||||
bl_label = "Render Icon"
|
||||
|
||||
filepath: bpy.props.StringProperty()
|
||||
use_viewport: bpy.props.BoolProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object is not None
|
||||
|
||||
def execute(self, context):
|
||||
state = pushRender()
|
||||
render = bpy.context.scene.render
|
||||
|
||||
print("Render!")
|
||||
|
||||
print("file", self.filepath)
|
||||
render.filepath = self.filepath
|
||||
res = 256
|
||||
render.resolution_x = res
|
||||
render.resolution_y = res
|
||||
render.film_transparent = True
|
||||
render.filter_size = 0.75
|
||||
|
||||
if self.use_viewport:
|
||||
bpy.ops.render.opengl(write_still=True, view_context=True)
|
||||
else:
|
||||
bpy.ops.render.render(write_still=True)
|
||||
|
||||
popRender(state)
|
||||
|
||||
pcoll = preview_collections["main"]
|
||||
print(pcoll) #.update.__doc__, pcoll.load.__doc__)
|
||||
#pcoll.clear(m
|
||||
if my_icon_name in pcoll:
|
||||
pcoll[my_icon_name].reload()
|
||||
else:
|
||||
pcoll.load(my_icon_name, my_icon_path, 'IMAGE', force_reload=True)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class PreviewsExamplePanel(bpy.types.Panel):
|
||||
"Creates a Panel in the Object properties window"
|
||||
bl_label = "Previews Example Panel"
|
||||
bl_idname = "OBJECT_PT_previews"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "object"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
pcoll = preview_collections["main"]
|
||||
|
||||
row = layout.row()
|
||||
my_icon = pcoll[my_icon_name]
|
||||
|
||||
print(my_icon_name, my_icon.icon_id)
|
||||
row.template_icon(my_icon.icon_id, scale=2)
|
||||
|
||||
props = row.operator("render.my_render_preview", icon_value=my_icon.icon_id)
|
||||
props["filepath"] = my_icon_path
|
||||
props["use_viewport"] = True
|
||||
|
||||
# my_icon.icon_id can be used in any UI function that accepts
|
||||
# icon_value # try also setting text=""
|
||||
# to get an icon only operator button
|
||||
|
||||
#"""
|
||||
|
||||
classes = [VIEW3D_PT_SculptPalette,
|
||||
#RenderPreview,
|
||||
WM_MT_button_context,
|
||||
SelectBrushTool,
|
||||
CallBrushMenu,
|
||||
BrushRef,
|
||||
SetBrushTool,
|
||||
AddToPalette,
|
||||
RemoveBrushTool,
|
||||
BrushPalette,
|
||||
BrushPaletteSet]
|
||||
|
||||
def post_register():
|
||||
bpy.types.Palette.brush_palette = PointerProperty(type=BrushPalette)
|
||||
bpy.types.WM_MT_button_context.append(menu_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not hasattr(bpy, "sculpt_global"):
|
||||
bpy.sculpt_global = []
|
||||
|
||||
for cls in bpy.sculpt_global:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
bpy.sculpt_global = []
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.sculpt_global.append(cls)
|
||||
|
||||
post_register()
|
|
@ -230,6 +230,14 @@ class _draw_tool_settings_context_mode:
|
|||
if (tool is None) or (not tool.has_datablock):
|
||||
return False
|
||||
|
||||
try:
|
||||
row = layout.row()
|
||||
row.operator_context = 'INVOKE_DEFAULT'
|
||||
row.scale_y = 1.25
|
||||
row.operator("sculpt.call_brush_palette", text="Palette")
|
||||
except:
|
||||
pass
|
||||
|
||||
paint = context.tool_settings.sculpt
|
||||
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
|
||||
|
||||
|
|
|
@ -280,6 +280,8 @@ MAKE_BOOL(use_weighted_smooth, "Weight By Area", "Weight by face area to get a s
|
|||
MAKE_BOOL_EX(preserve_faceset_boundary, "Preserve Faceset Boundary", "Preserve face set boundaries", true, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_BOOL_EX(hard_edge_mode, "Hard Edge Mode", "Treat face set boundaries as hard edges", false, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_BOOL(grab_silhouette, "Grab Silhouette", "Grabs trying to automask the silhouette of the object", false)
|
||||
MAKE_BOOL(use_grab_active_vertex, "Grab Active Vertex",
|
||||
"Apply the maximum grab strength to the active vertex instead of the cursor location", false)
|
||||
MAKE_FLOAT_EX_FLAG(dyntopo_detail_percent, "Detail Percent", "Detail Percent", 25.0f, 0.0f, 1000.0f, 0.0f, 1000.0f, false, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_FLOAT_EX_FLAG(dyntopo_detail_range, "Detail Range", "Detail Range", 0.45f, 0.01f, 0.99f, 0.01f, 0.99f, false, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_FLOAT_EX_FLAG(dyntopo_detail_size, "Detail Size", "Detail Size", 8.0f, 0.1f, 100.0f, 0.001f, 500.0f, false, BRUSH_CHANNEL_INHERIT)
|
||||
|
@ -522,9 +524,15 @@ MAKE_ENUM(elastic_deform_type, "Deformation", "Deformation type that is used in
|
|||
{BRUSH_ELASTIC_DEFORM_TWIST, "TWIST", "NONE", "Twist", ""},
|
||||
{-1}
|
||||
})
|
||||
MAKE_FLOAT(elastic_deform_volume_preservation, "Volume Preservation",
|
||||
"Poisson ratio for elastic deformation. Higher values preserve volume "
|
||||
"more, but also lead to more bulging", 0.0f, 0.9f, false)
|
||||
|
||||
MAKE_BOOL(use_ctrl_invert, "Use Ctrl Invert", "Take brush addition or subtraction mode into account", true)
|
||||
|
||||
MAKE_BOOL(use_smoothed_rake, "Smooth Raking", "Smooth angles of clay strips brush and raked textures", false)
|
||||
MAKE_BOOL(use_surface_falloff, "Use Surface Falloff",
|
||||
"Propagate the falloff of the brush trough the surface of the mesh", false)
|
||||
|
||||
//MAKE_FLOAT3_EX
|
||||
/* clang-format on */
|
||||
|
|
|
@ -445,6 +445,7 @@ static BrushSettingsMap brush_settings_map[] = {
|
|||
DEF(plane_offset, plane_offset, FLOAT, FLOAT)
|
||||
DEF(plane_trim, plane_trim, FLOAT, FLOAT)
|
||||
DEF(blend, blend, INT, INT)
|
||||
DEF(elastic_deform_volume_preservation, elastic_deform_volume_preservation, FLOAT, FLOAT)
|
||||
};
|
||||
|
||||
static const int brush_settings_map_len = ARRAY_SIZE(brush_settings_map);
|
||||
|
@ -510,6 +511,8 @@ BrushFlagMap brush_flags_map[] = {
|
|||
DEF(flag2, use_pose_lock_rotation, BRUSH_POSE_USE_LOCK_ROTATION)
|
||||
DEF(flag, use_space_attenuation, BRUSH_SPACE_ATTEN)
|
||||
DEF(flag, use_plane_trim, BRUSH_PLANE_TRIM)
|
||||
DEF(flag2, use_surface_falloff, BRUSH_USE_SURFACE_FALLOFF)
|
||||
DEF(flag2, use_grab_active_vertex, BRUSH_GRAB_ACTIVE_VERTEX)
|
||||
};
|
||||
|
||||
int brush_flags_map_len = ARRAY_SIZE(brush_flags_map);
|
||||
|
@ -886,6 +889,7 @@ void reset_clay_mappings(BrushChannelSet *chset, bool strips)
|
|||
BKE_curvemapping_changed(curve, true);
|
||||
}
|
||||
else {
|
||||
#if 0 // dunno if I've interpreted the original code's math right - joeedh
|
||||
//[[0,0], [0.250,0.050], [0.500,0.125], [0.750,0.422], [1,1]
|
||||
cuma->curve[0].x = 0.0f;
|
||||
cuma->curve[0].y = 0.55f;
|
||||
|
@ -893,6 +897,7 @@ void reset_clay_mappings(BrushChannelSet *chset, bool strips)
|
|||
cuma->curve[2].x = 1.0f;
|
||||
cuma->curve[2].y = 1.0f;
|
||||
BKE_curvemapping_changed(curve, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
mp = BRUSHSET_LOOKUP(chset, strength)->mappings + BRUSH_MAPPING_PRESSURE;
|
||||
|
@ -945,6 +950,8 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
ADDCH(radius_unit);
|
||||
ADDCH(unprojected_radius);
|
||||
|
||||
ADDCH(use_surface_falloff);
|
||||
|
||||
if (!BRUSHSET_LOOKUP(chset, use_smoothed_rake)) {
|
||||
BrushChannel *ch = ADDCH(use_smoothed_rake);
|
||||
|
||||
|
@ -1035,6 +1042,15 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
reset_clay_mappings(chset, false);
|
||||
}
|
||||
break;
|
||||
case SCULPT_TOOL_BLOB:
|
||||
ADDCH(crease_pinch_factor);
|
||||
break;
|
||||
case SCULPT_TOOL_GRAB:
|
||||
ADDCH(use_grab_active_vertex);
|
||||
break;
|
||||
case SCULPT_TOOL_ELASTIC_DEFORM:
|
||||
ADDCH(use_grab_active_vertex);
|
||||
break;
|
||||
case SCULPT_TOOL_CLAY_STRIPS:
|
||||
if (set_mappings) {
|
||||
reset_clay_mappings(chset, true);
|
||||
|
@ -1210,6 +1226,7 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
|
|||
switch (tool) {
|
||||
case SCULPT_TOOL_INFLATE:
|
||||
case SCULPT_TOOL_BLOB:
|
||||
SHOWCTX(crease_pinch_factor);
|
||||
case SCULPT_TOOL_DRAW:
|
||||
SHOWCTX(autosmooth);
|
||||
break;
|
||||
|
@ -1239,6 +1256,9 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
|
|||
SHOWCTX(normal_weight);
|
||||
SHOWWRK(normal_weight);
|
||||
|
||||
SHOWWRK(use_grab_active_vertex);
|
||||
SHOWCTX(use_grab_active_vertex);
|
||||
SHOWALL(grab_silhouette);
|
||||
break;
|
||||
case SCULPT_TOOL_CLAY_STRIPS:
|
||||
SHOWWRK(area_radius_factor);
|
||||
|
@ -1367,6 +1387,10 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
|
|||
SHOWWRK(deform_target);
|
||||
SHOWWRK(elastic_deform_type);
|
||||
|
||||
break;
|
||||
case SCULPT_TOOL_ELASTIC_DEFORM:
|
||||
SHOWWRK(elastic_deform_type);
|
||||
SHOWCTX(elastic_deform_type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1520,12 +1544,15 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
GETCH(radius)->mappings[BRUSH_MAPPING_PRESSURE].flag |= BRUSH_MAPPING_ENABLED;
|
||||
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag |= BRUSH_MAPPING_ENABLED;
|
||||
|
||||
GETCH(strength)->flag &= ~BRUSH_CHANNEL_INHERIT;
|
||||
|
||||
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
|
||||
|
||||
GETCH(tip_roundness)->fvalue = 0.18f;
|
||||
GETCH(normal_radius_factor)->fvalue = 1.35f;
|
||||
GETCH(strength)->fvalue = 0.8f;
|
||||
GETCH(accumulate)->ivalue = 1;
|
||||
GETCH(spacing)->fvalue = 7.0f;
|
||||
|
||||
BKE_brush_mapping_ensure_write(&GETCH(radius)->mappings[BRUSH_MAPPING_PRESSURE]);
|
||||
|
||||
|
@ -1544,6 +1571,7 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
break;
|
||||
case SCULPT_TOOL_THUMB:
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
|
||||
BRUSHSET_LOOKUP(chset, strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &=
|
||||
~BRUSH_MAPPING_ENABLED;
|
||||
|
@ -1581,9 +1609,11 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
GETCH(radius)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
break;
|
||||
case SCULPT_TOOL_ELASTIC_DEFORM:
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
|
||||
break;
|
||||
|
@ -1598,6 +1628,7 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
GETCH(dyntopo_mode)->flag = BRUSH_CHANNEL_INHERIT_IF_UNSET;
|
||||
GETCH(strength)->fvalue = 1.0f;
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
|
||||
break;
|
||||
case SCULPT_TOOL_DRAW_FACE_SETS:
|
||||
|
@ -1610,11 +1641,13 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
break;
|
||||
case SCULPT_TOOL_POSE:
|
||||
GETCH(strength)->mappings[BRUSH_MAPPING_PRESSURE].flag &= ~BRUSH_MAPPING_ENABLED;
|
||||
BRUSHSET_SET_BOOL(chset, use_space_attenuation, false);
|
||||
ADDCH(elastic_deform_type);
|
||||
ADDCH(elastic_deform_volume_preservation);
|
||||
break;
|
||||
default: {
|
||||
// implement me!
|
||||
|
|
|
@ -8685,6 +8685,7 @@ void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings
|
|||
case SCULPT_TOOL_ELASTIC_DEFORM:
|
||||
case SCULPT_TOOL_FAIRING:
|
||||
case SCULPT_TOOL_FILL:
|
||||
case SCULPT_TOOL_BLOB:
|
||||
case SCULPT_TOOL_FLATTEN:
|
||||
case SCULPT_TOOL_GRAB:
|
||||
case SCULPT_TOOL_LAYER:
|
||||
|
|
Loading…
Reference in New Issue