Merge GSOC Sculpt Branch: 28499-30319

https://svn.blender.org/svnroot/bf-blender/branches/soc-2010-jwilkins
See log of that branch for details.
This commit is contained in:
Jason Wilkins
2010-07-14 14:11:03 +00:00
parent ae1748b984
commit 5505697ac5
55 changed files with 5239 additions and 1374 deletions

View File

@@ -56,9 +56,8 @@ else:
if env['BF_GHOST_DEBUG']:
defs.append('BF_GHOST_DEBUG')
incs = '. ../string #extern/glew/include #source/blender/imbuf #source/blender/makesdna ' + env['BF_OPENGL_INC']
if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
incs = env['BF_WINTAB_INC'] + ' ' + incs
env.BlenderLib ('bf_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15] )

View File

@@ -42,7 +42,7 @@ AGLContext GHOST_WindowCarbon::s_firstaglCtx = NULL;
const GHOST_TInt32 GHOST_WindowCarbon::s_sizeRectSize = 16;
#endif //GHOST_DRAW_CARBON_GUTTER
static const GLint sPreferredFormatWindow[8] = {
static const GLint sPreferredFormatWindow[10] = {
AGL_RGBA,
AGL_DOUBLEBUFFER,
AGL_ACCELERATED,
@@ -50,7 +50,7 @@ AGL_DEPTH_SIZE, 32,
AGL_NONE,
};
static const GLint sPreferredFormatFullScreen[9] = {
static const GLint sPreferredFormatFullScreen[11] = {
AGL_RGBA,
AGL_DOUBLEBUFFER,
AGL_ACCELERATED,

View File

@@ -348,10 +348,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated;
//pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway
pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
if (numOfAASamples>0) {

View File

@@ -1093,7 +1093,7 @@ static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
( pfd.cDepthBits <= 8 ) ||
!(pfd.iPixelType == PFD_TYPE_RGBA) )
!(pfd.iPixelType == PFD_TYPE_RGBA))
return 0;
weight = 1; /* it's usable */

View File

@@ -437,6 +437,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
col.prop(md, "levels", text="Preview")
col.prop(md, "sculpt_levels", text="Sculpt")
col.prop(md, "render_levels", text="Render")
col.prop(bpy.context.tool_settings.sculpt, "fast_navigate")
if wide_ui:
col = split.column()

View File

@@ -275,15 +275,12 @@ class TEXTURE_PT_mapping(TextureSlotPanel):
if type(idblock) == bpy.types.Brush:
if context.sculpt_object:
layout.label(text="Brush Mapping:")
layout.prop(tex, "map_mode", expand=True)
row = layout.row()
row.active = tex.map_mode in ('FIXED', 'TILED')
row.prop(tex, "angle")
row = layout.row()
row.active = tex.map_mode in ('TILED', '3D')
row.column().prop(tex, "size")
else:
if type(idblock) == bpy.types.Material:
split = layout.split(percentage=0.3)
@@ -307,15 +304,17 @@ class TEXTURE_PT_mapping(TextureSlotPanel):
row.prop(tex, "y_mapping", text="")
row.prop(tex, "z_mapping", text="")
# any non brush
split = layout.split()
split = layout.split()
col = split.column()
col.prop(tex, "offset")
if wide_ui:
col = split.column()
col.prop(tex, "offset")
else:
col.separator()
if wide_ui:
col = split.column()
col.prop(tex, "size")
col.prop(tex, "size")
class TEXTURE_PT_influence(TextureSlotPanel):

View File

@@ -327,7 +327,21 @@ class USERPREF_PT_edit(bpy.types.Panel):
row.separator()
row.separator()
sculpt = context.tool_settings.sculpt
col = row.column()
col.label(text="Paint and Sculpt:")
col.prop(edit, "sculpt_paint_use_unified_size", text="Unify Size")
col.prop(edit, "sculpt_paint_use_unified_strength", text="Unify Strength")
row = col.row(align=True)
row.label("Overlay Color:")
row.prop(edit, "sculpt_paint_overlay_col", text="")
col.prop(sculpt, "use_openmp", text="Threaded Sculpt")
col.prop(sculpt, "show_brush")
col.separator()
col.separator()
col.separator()
col.label(text="Duplicate Data:")
col.prop(edit, "duplicate_mesh", text="Mesh")
col.prop(edit, "duplicate_surface", text="Surface")

View File

@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
narrowui = bpy.context.user_preferences.view.properties_width_check
class View3DPanel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
@@ -503,18 +504,26 @@ class VIEW3D_PT_tools_brush(PaintPanel):
if not context.particle_edit_object:
col = layout.split().column()
row = col.row()
if context.sculpt_object and brush:
defaultbrushes = 8
elif context.texture_paint_object and brush:
defaultbrushes = 4
if context.sculpt_object and context.tool_settings.sculpt:
col.template_ID_preview(settings, "brush", new="brush.add", filter="is_sculpt_brush", rows=3, cols=8)
elif context.texture_paint_object and context.tool_settings.image_paint:
col.template_ID_preview(settings, "brush", new="brush.add", filter="is_imapaint_brush", rows=3, cols=8)
elif context.vertex_paint_object and context.tool_settings.vertex_paint:
col.template_ID_preview(settings, "brush", new="brush.add", filter="is_vpaint_brush", rows=3, cols=8)
elif context.weight_paint_object and context.tool_settings.weight_paint:
col.template_ID_preview(settings, "brush", new="brush.add", filter="is_wpaint_brush", rows=3, cols=8)
else:
defaultbrushes = 7
row = col.row()
row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaultbrushes)
if context.sculpt_object and brush:
defaultbrushes = 8
elif context.texture_paint_object and brush:
defaultbrushes = 4
else:
defaultbrushes = 7
col.template_ID(settings, "brush", new="brush.add")
row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaultbrushes)
# Particle Mode #
@@ -546,44 +555,152 @@ class VIEW3D_PT_tools_brush(PaintPanel):
# Sculpt Mode #
elif context.sculpt_object and brush:
edit = context.user_preferences.edit
col = layout.column()
col.separator()
row = col.row(align=True)
row.prop(brush, "size", slider=True)
if brush.sculpt_tool != 'GRAB':
row.prop(brush, "use_size_pressure", toggle=True, text="")
if edit.sculpt_paint_use_unified_size:
if edit.sculpt_paint_unified_lock_brush_size:
row.prop(edit, "sculpt_paint_unified_lock_brush_size", toggle=True, text="", icon='LOCKED')
row.prop(edit, "sculpt_paint_unified_unprojected_radius", text="Unified Radius", slider=True)
else:
row.prop(edit, "sculpt_paint_unified_lock_brush_size", toggle=True, text="", icon='UNLOCKED')
row.prop(edit, "sculpt_paint_unified_size", text="Unified Radius", slider=True)
else:
if brush.lock_brush_size:
row.prop(brush, "lock_brush_size", toggle=True, text="", icon='LOCKED')
row.prop(brush, "unprojected_radius", text="Radius", slider=True)
else:
row.prop(brush, "lock_brush_size", toggle=True, text="", icon='UNLOCKED')
row.prop(brush, "size", text="Radius", slider=True)
row.prop(brush, "use_size_pressure", toggle=True, text="")
if brush.sculpt_tool not in ('SNAKE_HOOK', 'GRAB', 'ROTATE'):
col.separator()
row = col.row(align=True)
row.prop(brush, "strength", slider=True)
if brush.use_space and brush.sculpt_tool not in ('SMOOTH'):
if brush.use_space_atten:
row.prop(brush, "use_space_atten", toggle=True, text="", icon='LOCKED')
else:
row.prop(brush, "use_space_atten", toggle=True, text="", icon='UNLOCKED')
if edit.sculpt_paint_use_unified_strength:
row.prop(edit, "sculpt_paint_unified_strength", text="Unified Strength", slider=True)
else:
row.prop(brush, "strength", text="Strength", slider=True)
row.prop(brush, "use_strength_pressure", text="")
# XXX - TODO
#row = col.row(align=True)
#row.prop(brush, "jitter", slider=True)
#row.prop(brush, "use_jitter_pressure", toggle=True, text="")
col = layout.column()
if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'):
col.row().prop(brush, "direction", expand=True)
if brush.sculpt_tool not in ('SMOOTH'):
col.separator()
if brush.sculpt_tool in ('DRAW', 'INFLATE', 'LAYER'):
col.prop(brush, "use_accumulate")
row = col.row(align=True)
row.prop(brush, "autosmooth_factor", slider=True)
row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
if brush.sculpt_tool == 'LAYER':
ob = context.sculpt_object
do_persistent = True
# not supported yet for this case
for md in ob.modifiers:
if md.type == 'MULTIRES':
do_persistent = False
if do_persistent:
col.prop(brush, "use_persistent")
col.operator("sculpt.set_persistent_base")
if brush.sculpt_tool in ('GRAB', 'SNAKE_HOOK'):
col.separator()
row = col.row(align=True)
row.prop(brush, "normal_weight", slider=True)
if brush.sculpt_tool in ('CREASE', 'BLOB'):
col.separator()
row = col.row(align=True)
row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
if brush.sculpt_tool not in ('PINCH', 'INFLATE', 'SMOOTH'):
row = col.row(align=True)
col.separator()
if brush.use_original_normal:
row.prop(brush, "use_original_normal", toggle=True, text="", icon='LOCKED')
else:
row.prop(brush, "use_original_normal", toggle=True, text="", icon='UNLOCKED')
row.prop(brush, "sculpt_plane", text="")
#if brush.sculpt_tool in ('CLAY', 'CLAY_TUBES', 'FLATTEN', 'FILL', 'SCRAPE'):
if brush.sculpt_tool in ('CLAY', 'FLATTEN', 'FILL', 'SCRAPE'):
row = col.row(align=True)
row.prop(brush, "plane_offset", slider=True)
row.prop(brush, "use_offset_pressure", text="")
col.separator()
row= col.row()
row.prop(brush, "use_plane_trim", text="Trim")
row= col.row()
row.active=brush.use_plane_trim
row.prop(brush, "plane_trim", slider=True, text="Distance")
col.separator()
row= col.row()
row.prop(brush, "use_frontface", text="Front Faces Only")
#if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'LAYER', 'CLAY', 'CLAY_TUBES'):
if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'LAYER', 'CLAY'):
col.separator()
col.row().prop(brush, "direction", expand=True)
elif brush.sculpt_tool in ('FLATTEN'):
col.separator()
col.row().prop(brush, "flatten_contrast", expand=True)
elif brush.sculpt_tool in ('FILL'):
col.separator()
col.row().prop(brush, "fill_deepen", expand=True)
elif brush.sculpt_tool in ('SCRAPE'):
col.separator()
col.row().prop(brush, "scrape_peaks", expand=True)
elif brush.sculpt_tool in ('INFLATE'):
col.separator()
col.row().prop(brush, "inflate_deflate", expand=True)
elif brush.sculpt_tool in ('PINCH'):
col.separator()
col.row().prop(brush, "pinch_magnify", expand=True)
#if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'INFLATE', 'LAYER', 'CLAY', 'CLAY_TUBES'):
if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'INFLATE', 'LAYER', 'CLAY'):
col.separator()
col.prop(brush, "use_accumulate")
if brush.sculpt_tool == 'LAYER':
col.separator()
ob = context.sculpt_object
do_persistent = True
# not supported yet for this case
for md in ob.modifiers:
if md.type == 'MULTIRES':
do_persistent = False
if do_persistent:
col.prop(brush, "use_persistent")
col.operator("sculpt.set_persistent_base")
# Texture Paint Mode #
@@ -669,10 +786,88 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel):
col = layout.column()
col.template_ID_preview(brush, "texture", new="texture.new", rows=2, cols=4)
col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
if context.sculpt_object:
col.row().prop(tex_slot, "map_mode", expand=True)
#XXX duplicated from properties_texture.py
wide_ui = context.region.width > narrowui
col.separator()
col.label(text="Brush Mapping:")
row = col.row(align=True)
row.prop(tex_slot, "map_mode", expand=True)
col.separator()
col = layout.column()
col.active = tex_slot.map_mode in ('FIXED')
col.label(text="Angle:")
col = layout.column()
if not brush.use_anchor and brush.sculpt_tool not in ('GRAB', 'SNAKE_HOOK', 'THUMB', 'ROTATE') and tex_slot.map_mode in ('FIXED'):
col.prop(brush, "texture_angle_source", text="")
else:
col.prop(brush, "texture_angle_source_no_random", text="")
#row = col.row(align=True)
#row.label(text="Angle:")
#row.active = tex_slot.map_mode in ('FIXED', 'TILED')
#row = col.row(align=True)
#col = row.column()
#col.active = tex_slot.map_mode in ('FIXED')
#col.prop(brush, "use_rake", toggle=True, icon='PARTICLEMODE', text="")
col = layout.column()
col.prop(tex_slot, "angle", text="")
col.active = tex_slot.map_mode in ('FIXED', 'TILED')
#col = layout.column()
#col.prop(brush, "use_random_rotation")
#col.active = (not brush.use_rake) and (not brush.use_anchor) and brush.sculpt_tool not in ('GRAB', 'SNAKE_HOOK', 'THUMB', 'ROTATE') and tex_slot.map_mode in ('FIXED')
split = layout.split()
col = split.column()
col.prop(tex_slot, "offset")
if wide_ui:
col = split.column()
else:
col.separator()
col.prop(tex_slot, "size")
col = layout.column()
row = col.row(align=True)
row.label(text="Sample Bias:")
row = col.row(align=True)
row.prop(brush, "texture_sample_bias", slider=True, text="")
row = col.row(align=True)
row.label(text="Overlay:")
row.active = tex_slot.map_mode in ('FIXED', 'TILED')
row = col.row(align=True)
col = row.column()
if brush.use_texture_overlay:
col.prop(brush, "use_texture_overlay", toggle=True, text="", icon='MUTE_IPO_OFF')
else:
col.prop(brush, "use_texture_overlay", toggle=True, text="", icon='MUTE_IPO_ON')
col.active = tex_slot.map_mode in ('FIXED', 'TILED')
col = row.column()
col.prop(brush, "texture_overlay_alpha", text="Alpha")
col.active = tex_slot.map_mode in ('FIXED', 'TILED') and brush.use_texture_overlay
class VIEW3D_PT_tools_brush_tool(PaintPanel):
@@ -696,15 +891,11 @@ class VIEW3D_PT_tools_brush_tool(PaintPanel):
col = layout.column(align=True)
if context.sculpt_object:
col.prop(brush, "sculpt_tool", expand=True)
col.prop(brush, "sculpt_tool", expand=False, text="")
elif context.texture_paint_object:
col.prop(brush, "imagepaint_tool", expand=True)
#col.prop_enum(settings, "tool", 'DRAW')
#col.prop_enum(settings, "tool", 'SOFTEN')
#col.prop_enum(settings, "tool", 'CLONE')
#col.prop_enum(settings, "tool", 'SMEAR')
col.prop(brush, "imagepaint_tool", expand=False, text="")
elif context.vertex_paint_object or context.weight_paint_object:
col.prop(brush, "vertexpaint_tool", expand=True)
col.prop(brush, "vertexpaint_tool", expand=False, text="")
class VIEW3D_PT_tools_brush_stroke(PaintPanel):
@@ -725,29 +916,83 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel):
brush = settings.brush
texture_paint = context.texture_paint_object
if context.sculpt_object:
if brush.sculpt_tool != 'LAYER':
layout.prop(brush, "use_anchor")
layout.prop(brush, "use_rake")
layout.prop(brush, "use_airbrush")
col = layout.column()
col.active = brush.use_airbrush
col.prop(brush, "rate", slider=True)
if not texture_paint:
layout.prop(brush, "use_smooth_stroke")
if context.sculpt_object:
col.label(text="Stroke Method:")
col.prop(brush, "stroke_method", text="")
if brush.use_anchor:
col.separator()
row = col.row()
row.prop(brush, "edge_to_edge", "Edge To Edge")
if brush.use_airbrush:
col.separator()
row = col.row()
row.prop(brush, "rate", text="Rate", slider=True)
if brush.use_space:
col.separator()
row = col.row()
row.active = brush.use_space
row.prop(brush, "spacing", text="Spacing")
if brush.sculpt_tool not in ('GRAB', 'THUMB', 'SNAKE_HOOK', 'ROTATE') and (not brush.use_anchor) and (not brush.restore_mesh):
col = layout.column()
col.separator()
col.prop(brush, "use_smooth_stroke")
sub = col.column()
sub.active = brush.use_smooth_stroke
sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
col.separator()
row = col.row(align=True)
row.prop(brush, "jitter", slider=True)
row.prop(brush, "use_jitter_pressure", toggle=True, text="")
else:
row = col.row()
row.prop(brush, "use_airbrush")
row = col.row()
row.active = brush.use_airbrush and (not brush.use_space) and (not brush.use_anchor)
row.prop(brush, "rate", slider=True)
col.separator()
if not texture_paint:
row = col.row()
row.prop(brush, "use_smooth_stroke")
col = layout.column()
col.active = brush.use_smooth_stroke
col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
col.separator()
col = layout.column()
col.active = brush.use_smooth_stroke
col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
col.active = (not brush.use_anchor) and (brush.sculpt_tool not in ('GRAB', 'THUMB', 'ROTATE', 'SNAKE_HOOK'))
layout.prop(brush, "use_space")
row = layout.row(align=True)
row.active = brush.use_space
row.prop(brush, "spacing", text="Distance", slider=True)
if texture_paint:
row.prop(brush, "use_spacing_pressure", toggle=True, text="")
row = col.row()
row.prop(brush, "use_space")
row = col.row()
row.active = brush.use_space
row.prop(brush, "spacing", text="Spacing")
#col.prop(brush, "use_space_atten", text="Adaptive Strength")
#col.prop(brush, "use_adaptive_space", text="Adaptive Spacing")
#col.separator()
#if texture_paint:
# row.prop(brush, "use_spacing_pressure", toggle=True, text="")
class VIEW3D_PT_tools_brush_curve(PaintPanel):
@@ -767,13 +1012,17 @@ class VIEW3D_PT_tools_brush_curve(PaintPanel):
layout.template_curve_mapping(brush, "curve", brush=True)
row = layout.row(align=True)
row.operator("brush.curve_preset", text="Sharp").shape = 'SHARP'
row.operator("brush.curve_preset", text="Smooth").shape = 'SMOOTH'
row.operator("brush.curve_preset", text="Max").shape = 'MAX'
row.operator("brush.curve_preset", icon="SMOOTHCURVE", text="").shape = 'SMOOTH'
row.operator("brush.curve_preset", icon="SPHERECURVE", text="").shape = 'ROUND'
row.operator("brush.curve_preset", icon="ROOTCURVE", text="").shape = 'ROOT'
row.operator("brush.curve_preset", icon="SHARPCURVE", text="").shape = 'SHARP'
row.operator("brush.curve_preset", icon="LINCURVE", text="").shape = 'LINE'
row.operator("brush.curve_preset", icon="NOCURVE", text="").shape = 'MAX'
row.operator("brush.curve_preset", icon="RNDCURVE", text="").shape = 'MID9'
class VIEW3D_PT_sculpt_options(PaintPanel):
bl_label = "Options"
bl_default_closed = True
def poll(self, context):
return (context.sculpt_object and context.tool_settings.sculpt)
@@ -781,25 +1030,100 @@ class VIEW3D_PT_sculpt_options(PaintPanel):
def draw(self, context):
layout = self.layout
wide_ui = context.region.width > narrowui
sculpt = context.tool_settings.sculpt
settings = self.paint_settings(context)
brush = settings.brush
col = layout.column()
col.prop(sculpt, "show_brush")
col.prop(sculpt, "fast_navigate")
split = self.layout.split()
split = layout.split()
col = split.column()
col.label(text="Symmetry:")
edit = context.user_preferences.edit
col.label(text="Unified Settings:")
col.prop(edit, "sculpt_paint_use_unified_size", text="Size")
col.prop(edit, "sculpt_paint_use_unified_strength", text="Strength")
if wide_ui:
col = split.column()
else:
col.separator()
col.label(text="Lock:")
row = col.row(align=True)
row.prop(sculpt, "lock_x", text="X", toggle=True)
row.prop(sculpt, "lock_y", text="Y", toggle=True)
row.prop(sculpt, "lock_z", text="Z", toggle=True)
class VIEW3D_PT_sculpt_symmetry(PaintPanel):
bl_label = "Symmetry"
bl_default_closed = True
def poll(self, context):
return (context.sculpt_object and context.tool_settings.sculpt)
def draw(self, context):
wide_ui = context.region.width > narrowui
layout = self.layout
sculpt = context.tool_settings.sculpt
settings = self.paint_settings(context)
brush = settings.brush
split = layout.split()
col = split.column()
col.label(text="Mirror:")
col.prop(sculpt, "symmetry_x", text="X")
col.prop(sculpt, "symmetry_y", text="Y")
col.prop(sculpt, "symmetry_z", text="Z")
col = split.column()
col.label(text="Lock:")
col.prop(sculpt, "lock_x", text="X")
col.prop(sculpt, "lock_y", text="Y")
col.prop(sculpt, "lock_z", text="Z")
if wide_ui:
col = split.column()
else:
col.separator()
col.prop(sculpt, "radial_symm", text="Radial")
col = layout.column()
col.separator()
col.prop(sculpt, "use_symmetry_feather", text="Feather")
class VIEW3D_PT_tools_brush_appearance(PaintPanel):
bl_label = "Appearance"
bl_default_closed = True
def poll(self, context):
return (context.sculpt_object and context.tool_settings.sculpt) or (context.vertex_paint_object and context.tool_settings.vertex_paint) or (context.weight_paint_object and context.tool_settings.weight_paint) or (context.texture_paint_object and context.tool_settings.image_paint)
def draw(self, context):
layout = self.layout
sculpt = context.tool_settings.sculpt
settings = self.paint_settings(context)
brush = settings.brush
col = layout.column();
if context.sculpt_object and context.tool_settings.sculpt:
#if brush.sculpt_tool in ('DRAW', 'INFLATE', 'CLAY', 'CLAY_TUBES', 'PINCH', 'CREASE', 'BLOB', 'FLATTEN'):
if brush.sculpt_tool in ('DRAW', 'INFLATE', 'CLAY', 'PINCH', 'CREASE', 'BLOB', 'FLATTEN'):
col.prop(brush, "add_col", text="Add Color")
col.prop(brush, "sub_col", text="Substract Color")
else:
col.prop(brush, "add_col", text="Color")
col.separator()
col = layout.column()
col.label(text="Icon:")
#col.template_ID_preview(brush, "image_icon", open="image.open", filter="is_image_icon", rows=3, cols=8)
col.template_ID_preview(brush, "image_icon", open="image.open", rows=3, cols=8)
# ********** default tools for weightpaint ****************
@@ -1049,9 +1373,11 @@ classes = [
VIEW3D_PT_tools_posemode_options,
VIEW3D_PT_tools_brush,
VIEW3D_PT_tools_brush_texture,
VIEW3D_PT_tools_brush_tool,
VIEW3D_PT_tools_brush_stroke,
VIEW3D_PT_tools_brush_curve,
VIEW3D_PT_tools_brush_appearance,
VIEW3D_PT_tools_brush_tool,
VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_options,
VIEW3D_PT_tools_vertexpaint,
VIEW3D_PT_tools_weightpaint_options,

View File

@@ -43,9 +43,9 @@ struct bContext;
struct ReportList;
struct Scene;
struct Main;
#define BLENDER_VERSION 252
#define BLENDER_SUBVERSION 5
#define BLENDER_SUBVERSION 6 // XXX: this shouldn't be merged with trunk, this is so Sculpt branch can detect old files
#define BLENDER_MINVERSION 250
#define BLENDER_MINSUBVERSION 0

View File

@@ -84,5 +84,15 @@ unsigned int *brush_gen_texture_cache(struct Brush *br, int half_side);
void brush_radial_control_invoke(struct wmOperator *op, struct Brush *br, float size_weight);
int brush_radial_control_exec(struct wmOperator *op, struct Brush *br, float size_weight);
/* unified strength and size */
int sculpt_get_brush_size(struct Brush *brush);
void sculpt_set_brush_size(struct Brush *brush, int size);
int sculpt_get_lock_brush_size(struct Brush *brush);
float sculpt_get_brush_unprojected_radius(struct Brush *brush);
void sculpt_set_brush_unprojected_radius(struct Brush *brush, float unprojected_radius);
float sculpt_get_brush_alpha(struct Brush *brush);
void sculpt_set_brush_alpha(struct Brush *brush, float alpha);
#endif

View File

@@ -28,6 +28,8 @@
#ifndef BKE_PAINT_H
#define BKE_PAINT_H
#include "DNA_vec_types.h"
struct Brush;
struct MFace;
struct MultireModifierData;
@@ -96,6 +98,8 @@ typedef struct SculptSession {
struct GPUDrawObject *drawobject;
int modifiers_active;
rcti previous_r;
} SculptSession;
void free_sculptsession(struct Object *ob);

View File

@@ -53,8 +53,7 @@
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BKE_icons.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -70,29 +69,59 @@ Brush *add_brush(const char *name)
brush= alloc_libblock(&G.main->brush, ID_BR, name);
brush->rgb[0]= 1.0f;
/* BRUSH SCULPT TOOL SETTINGS */
brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
brush->size= 35; /* radius of the brush in pixels */
brush->alpha= 0.5f; /* brush strength/intensity probably variable should be renamed? */
brush->autosmooth_factor= 0.0f;
brush->crease_pinch_factor= 0.5f;
brush->sculpt_plane = SCULPT_DISP_DIR_VIEW;
brush->plane_offset= 0.0f; /* how far above or below the plane that is found by averaging the faces */
brush->plane_trim= 0.5f;
brush->clone.alpha= 0.5f;
brush->normal_weight= 0.0f;
/* BRUSH PAINT TOOL SETTINGS */
brush->rgb[0]= 1.0f; /* default rgb color of the brush when painting - white */
brush->rgb[1]= 1.0f;
brush->rgb[2]= 1.0f;
brush->alpha= 0.2f;
brush->size= 25;
brush->spacing= 3.5f;
brush->smooth_stroke_radius= 75;
brush->smooth_stroke_factor= 0.9;
brush->rate= 0.1f;
brush->jitter= 0.0f;
brush->clone.alpha= 0.5;
brush->sculpt_tool = SCULPT_TOOL_DRAW;
brush->flag |= BRUSH_SPACE;
brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
/* BRUSH STROKE SETTINGS */
brush->flag |= (BRUSH_SPACE|BRUSH_SPACE_ATTEN);
brush->spacing= 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
brush->smooth_stroke_radius= 75;
brush->smooth_stroke_factor= 0.9f;
brush->rate= 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */
brush->jitter= 0.0f;
/* BRUSH TEXTURE SETTINGS */
default_mtex(&brush->mtex);
brush->texture_sample_bias= 0; /* value to added to texture samples */
/* brush appearance */
brush->image_icon= NULL;
brush->add_col[0]= 1.00; /* add mode color is light red */
brush->add_col[1]= 0.39;
brush->add_col[2]= 0.39;
brush->sub_col[0]= 0.39; /* subtract mode color is light blue */
brush->sub_col[1]= 0.39;
brush->sub_col[2]= 1.00;
/* the default alpha falloff curve */
brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
/* enable fake user by default */
brush->id.flag |= LIB_FAKEUSER;
brush_toggled_fake_user(brush);
return brush;
return brush;
}
Brush *copy_brush(Brush *brush)
@@ -118,7 +147,7 @@ Brush *copy_brush(Brush *brush)
void free_brush(Brush *brush)
{
if(brush->mtex.tex) brush->mtex.tex->id.us--;
curvemapping_free(brush->curve);
}
@@ -731,11 +760,19 @@ static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pres
brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure));
}
static void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
{
if(brush->jitter){
jitterpos[0] = pos[0] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
jitterpos[1] = pos[1] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
float rand_pos[2];
// find random position within a circle of diameter 1
do {
rand_pos[0] = BLI_frand()-0.5f;
rand_pos[1] = BLI_frand()-0.5f;
} while (len_v2(rand_pos) > 0.5f);
jitterpos[0] = pos[0] + 2*rand_pos[0]*brush->size*brush->jitter;
jitterpos[1] = pos[1] + 2*rand_pos[1]*brush->size*brush->jitter;
}
else {
VECCOPY2D(jitterpos, pos);
@@ -887,7 +924,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
/* Uses the brush curve control to find a strength value between 0 and 1 */
float brush_curve_strength_clamp(Brush *br, float p, const float len)
{
if(p >= len) p= 1.0f;
if(p >= len) return 0;
else p= p/len;
p= curvemapping_evaluateF(br->curve, 0, p);
@@ -899,9 +936,12 @@ float brush_curve_strength_clamp(Brush *br, float p, const float len)
* used for sculpt only */
float brush_curve_strength(Brush *br, float p, const float len)
{
if(p >= len) p= 1.0f;
else p= p/len;
return curvemapping_evaluateF(br->curve, 0, p);
if(p >= len)
p= 1.0f;
else
p= p/len;
return curvemapping_evaluateF(br->curve, 0, p);
}
/* TODO: should probably be unified with BrushPainter stuff? */
@@ -915,7 +955,7 @@ unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
memset(&texres, 0, sizeof(TexResult));
if(mtex && mtex->tex) {
if(mtex->tex) {
float x, y, step = 2.0 / side, co[3];
texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
@@ -993,9 +1033,9 @@ void brush_radial_control_invoke(wmOperator *op, Brush *br, float size_weight)
float original_value= 0;
if(mode == WM_RADIALCONTROL_SIZE)
original_value = br->size * size_weight;
original_value = sculpt_get_brush_size(br) * size_weight;
else if(mode == WM_RADIALCONTROL_STRENGTH)
original_value = br->alpha;
original_value = sculpt_get_brush_alpha(br);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)
@@ -1013,9 +1053,15 @@ int brush_radial_control_exec(wmOperator *op, Brush *br, float size_weight)
const float conv = 0.017453293;
if(mode == WM_RADIALCONTROL_SIZE)
br->size = new_value * size_weight;
if (sculpt_get_lock_brush_size(br)) {
float initial_value = RNA_float_get(op->ptr, "initial_value");
const float unprojected_radius = sculpt_get_brush_unprojected_radius(br);
sculpt_set_brush_unprojected_radius(br, unprojected_radius * new_value/initial_value * size_weight);
}
else
sculpt_set_brush_size(br, new_value * size_weight);
else if(mode == WM_RADIALCONTROL_STRENGTH)
br->alpha = new_value;
sculpt_set_brush_alpha(br, new_value);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)

View File

@@ -126,6 +126,9 @@ CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, floa
cumap->cm[a].curve[1].x= maxx;
cumap->cm[a].curve[1].y= maxy;
}
cumap->changed_timestamp = 0;
return cumap;
}
@@ -240,10 +243,12 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
switch(preset) {
case CURVE_PRESET_LINE: cuma->totpoint= 2; break;
case CURVE_PRESET_SHARP: cuma->totpoint= 3; break;
case CURVE_PRESET_SHARP: cuma->totpoint= 4; break;
case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break;
case CURVE_PRESET_MAX: cuma->totpoint= 2; break;
case CURVE_PRESET_MID9: cuma->totpoint= 9;
case CURVE_PRESET_MID9: cuma->totpoint= 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint= 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint= 4; break;
}
cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points");
@@ -251,27 +256,29 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
switch(preset) {
case CURVE_PRESET_LINE:
cuma->curve[0].x= clipr->xmin;
cuma->curve[0].y= clipr->ymin;
cuma->curve[0].y= clipr->ymax;
cuma->curve[0].flag= 0;
cuma->curve[1].x= clipr->xmax;
cuma->curve[1].y= clipr->ymax;
cuma->curve[1].y= clipr->ymin;
cuma->curve[1].flag= 0;
break;
case CURVE_PRESET_SHARP:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
cuma->curve[1].x= 0.33;
cuma->curve[1].y= 0.33;
cuma->curve[2].x= 1;
cuma->curve[2].y= 0;
cuma->curve[1].x= 0.25;
cuma->curve[1].y= 0.50;
cuma->curve[2].x= 0.75;
cuma->curve[2].y= 0.04;
cuma->curve[3].x= 1;
cuma->curve[3].y= 0;
break;
case CURVE_PRESET_SMOOTH:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
cuma->curve[1].x= 0.25;
cuma->curve[1].y= 0.92;
cuma->curve[1].y= 0.94;
cuma->curve[2].x= 0.75;
cuma->curve[2].y= 0.08;
cuma->curve[2].y= 0.06;
cuma->curve[3].x= 1;
cuma->curve[3].y= 0;
break;
@@ -290,8 +297,29 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
cuma->curve[i].y= 0.5;
}
}
break;
case CURVE_PRESET_ROUND:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
cuma->curve[1].x= 0.5;
cuma->curve[1].y= 0.90;
cuma->curve[2].x= 0.86;
cuma->curve[2].y= 0.5;
cuma->curve[3].x= 1;
cuma->curve[3].y= 0;
break;
case CURVE_PRESET_ROOT:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
cuma->curve[1].x= 0.25;
cuma->curve[1].y= 0.95;
cuma->curve[2].x= 0.75;
cuma->curve[2].y= 0.44;
cuma->curve[3].x= 1;
cuma->curve[3].y= 0;
break;
}
if(cuma->table) {
MEM_freeN(cuma->table);
cuma->table= NULL;
@@ -619,7 +647,9 @@ void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
float thresh= 0.01f*(clipr->xmax - clipr->xmin);
float dx= 0.0f, dy= 0.0f;
int a;
cumap->changed_timestamp++;
/* clamp with clip */
if(cumap->flag & CUMA_DO_CLIP) {
for(a=0; a<cuma->totpoint; a++) {
@@ -701,7 +731,7 @@ float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
if(cuma->table==NULL) {
curvemap_make_table(cuma, &cumap->clipr);
if(cuma->table==NULL)
return value;
return 1.0f-value;
}
return curvemap_evaluateF(cuma, value);
}

View File

@@ -38,6 +38,7 @@
#include "DNA_material_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "BLI_ghash.h"
@@ -120,6 +121,7 @@ struct PreviewImage* BKE_previewimg_create()
for (i=0; i<PREVIEW_MIPMAPS; ++i) {
prv_img->changed[i] = 1;
prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
@@ -202,7 +204,7 @@ PreviewImage* BKE_previewimg_get(ID *id)
Image *img = (Image*)id;
if (!img->preview) img->preview = BKE_previewimg_create();
prv_img = img->preview;
}
}
return prv_img;
}
@@ -224,6 +226,7 @@ void BKE_icon_changed(int id)
int i;
for (i=0; i<PREVIEW_MIPMAPS; ++i) {
prv->changed[i] = 1;
prv->changed_timestamp[i]++;
}
}
}

View File

@@ -200,9 +200,9 @@ void free_image(Image *ima)
}
BKE_icon_delete(&ima->id);
ima->id.icon_id = 0;
if (ima->preview) {
BKE_previewimg_free(&ima->preview);
}
BKE_previewimg_free(&ima->preview);
for(a=0; a<IMA_MAX_RENDER_SLOT; a++) {
if(ima->renders[a]) {
RE_FreeRenderResult(ima->renders[a]);

View File

@@ -36,12 +36,17 @@ struct ListBase;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
typedef struct {
float (*co)[3];
} PBVHProxyNode;
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float* tmin);
/* Building */
@@ -70,7 +75,7 @@ void BLI_pbvh_search_gather(PBVH *bvh,
it's up to the callback to find the primitive within the leaves that is
hit first */
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original);
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
float ray_start[3], float ray_normal[3], float *dist);
@@ -106,6 +111,8 @@ void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
float BLI_pbvh_node_get_tmin(PBVHNode* node);
/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
@@ -159,13 +166,21 @@ typedef struct PBVHVertexIter {
float *fno;
} PBVHVertexIter;
#ifdef _MSC_VER
#pragma warning (disable:4127) // conditional expression is constant
#endif
#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \
{ \
struct DMGridData **grids; \
struct MVert *verts; \
int *grid_indices, totgrid, gridsize, *vert_indices, uniq_verts, totvert; \
\
memset(&vi, 0, sizeof(PBVHVertexIter)); \
vi.grid= 0; \
vi.no= 0; \
vi.fno= 0; \
vi.mvert= 0; \
vi.skip= 0; \
\
BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); \
BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); \
@@ -222,6 +237,13 @@ typedef struct PBVHVertexIter {
} \
}
void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count);
void BLI_pbvh_node_free_proxies(PBVHNode* node);
PBVHProxyNode* BLI_pbvh_node_add_proxy(PBVH* bvh, PBVHNode* node);
void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** nodes, int* totnode);
//void BLI_pbvh_node_BB_reset(PBVHNode* node);
//void BLI_pbvh_node_BB_expand(PBVHNode* node, float co[3]);
#endif /* BLI_PBVH_H */

View File

@@ -62,6 +62,7 @@ float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const floa
n[0]= n1[1]*n2[2]-n1[2]*n2[1];
n[1]= n1[2]*n2[0]-n1[0]*n2[2];
n[2]= n1[0]*n2[1]-n1[1]*n2[0];
return normalize_v3(n);
}
@@ -401,16 +402,17 @@ int isect_line_tri_v3(float p1[3], float p2[3], float v0[3], float v1[3], float
sub_v3_v3v3(s, p1, v0);
cross_v3_v3v3(q, s, e1);
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0)||(*lambda > 1.0)) return 0;
u = f * dot_v3v3(s, p);
if ((u < 0.0)||(u > 1.0)) return 0;
v = f * dot_v3v3(d, q);
cross_v3_v3v3(q, s, e1);
v = f * dot_v3v3(d, q);
if ((v < 0.0)||((u + v) > 1.0)) return 0;
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0)||(*lambda > 1.0)) return 0;
if(uv) {
uv[0]= u;
uv[1]= v;
@@ -440,17 +442,18 @@ int isect_ray_tri_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2
sub_v3_v3v3(s, p1, v0);
cross_v3_v3v3(q, s, e1);
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0)) return 0;
u = f * dot_v3v3(s, p);
if ((u < 0.0)||(u > 1.0)) return 0;
cross_v3_v3v3(q, s, e1);
v = f * dot_v3v3(d, q);
if ((v < 0.0)||((u + v) > 1.0)) return 0;
if(uv) {
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0)) return 0;
if(uv) {
uv[0]= u;
uv[1]= v;
}
@@ -460,36 +463,36 @@ int isect_ray_tri_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2
int isect_ray_tri_epsilon_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float epsilon)
{
float p[3], s[3], e1[3], e2[3], q[3];
float a, f, u, v;
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
cross_v3_v3v3(p, d, e2);
a = dot_v3v3(e1, p);
if (a == 0.0f) return 0;
f = 1.0f/a;
sub_v3_v3v3(s, p1, v0);
cross_v3_v3v3(q, s, e1);
float p[3], s[3], e1[3], e2[3], q[3];
float a, f, u, v;
u = f * dot_v3v3(s, p);
if ((u < -epsilon)||(u > 1.0f+epsilon)) return 0;
v = f * dot_v3v3(d, q);
if ((v < -epsilon)||((u + v) > 1.0f+epsilon)) return 0;
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0f)) return 0;
cross_v3_v3v3(p, d, e2);
a = dot_v3v3(e1, p);
if (a == 0.0f) return 0;
f = 1.0f/a;
if(uv) {
uv[0]= u;
uv[1]= v;
}
return 1;
sub_v3_v3v3(s, p1, v0);
u = f * dot_v3v3(s, p);
if ((u < -epsilon)||(u > 1.0f+epsilon)) return 0;
cross_v3_v3v3(q, s, e1);
v = f * dot_v3v3(d, q);
if ((v < -epsilon)||((u + v) > 1.0f+epsilon)) return 0;
*lambda = f * dot_v3v3(e2, q);
if ((*lambda < 0.0f)) return 0;
if(uv) {
uv[0]= u;
uv[1]= v;
}
return 1;
}
int isect_ray_tri_threshold_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold)

View File

@@ -92,6 +92,11 @@ struct PBVHNode {
unsigned int uniq_verts, face_verts;
char flag;
float tmin; // used for raycasting, is how close bb is to the ray point
int proxy_count;
PBVHProxyNode* proxies;
};
struct PBVH {
@@ -227,6 +232,17 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node)
node->vb= vb;
}
//void BLI_pbvh_node_BB_reset(PBVHNode* node)
//{
// BB_reset(&node->vb);
//}
//
//void BLI_pbvh_node_BB_expand(PBVHNode* node, float co[3])
//{
// BB_expand(&node->vb, co);
//}
/* Adapted from BLI_kdopbvh.c */
/* Returns the index of the first element on the right of the partition */
static int partition_indices(int *prim_indices, int lo, int hi, int axis,
@@ -354,10 +370,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
if(!G.background) {
node->draw_buffers =
GPU_build_mesh_buffers(map, bvh->verts, bvh->faces,
node->prim_indices,
node->totprim, node->vert_indices,
node->uniq_verts,
node->uniq_verts + node->face_verts);
node->prim_indices,
node->totprim, node->vert_indices,
node->uniq_verts,
node->uniq_verts + node->face_verts);
}
node->flag |= PBVH_UpdateDrawBuffers;
@@ -641,13 +657,12 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
{
PBVHNode *node;
int revisiting;
void *search_data;
/* purpose here is to traverse tree, visiting child nodes before their
parents, this order is necessary for e.g. computing bounding boxes */
while(iter->stacksize) {
/* pop node */
/* pop node */
iter->stacksize--;
node= iter->stack[iter->stacksize].node;
@@ -662,10 +677,7 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
if(revisiting)
return node;
/* check search callback */
search_data= iter->search_data;
if(iter->scb && !iter->scb(node, search_data))
if(iter->scb && !iter->scb(node, iter->search_data))
continue; /* don't traverse, outside of search zone */
if(node->flag & PBVH_Leaf) {
@@ -685,6 +697,34 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
return NULL;
}
static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
{
PBVHNode *node;
while(iter->stacksize) {
/* pop node */
iter->stacksize--;
node= iter->stack[iter->stacksize].node;
/* on a mesh with no faces this can happen
* can remove this check if we know meshes have at least 1 face */
if(node==NULL) return NULL;
if(iter->scb && !iter->scb(node, iter->search_data)) continue; /* don't traverse, outside of search zone */
if(node->flag & PBVH_Leaf) {
/* immediately hit leaf node */
return node;
}
else {
pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset+1, 0);
pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset, 0);
}
}
return NULL;
}
void BLI_pbvh_search_gather(PBVH *bvh,
BLI_pbvh_SearchCallback scb, void *search_data,
PBVHNode ***r_array, int *r_tot)
@@ -736,12 +776,105 @@ void BLI_pbvh_search_callback(PBVH *bvh,
pbvh_iter_begin(&iter, bvh, scb, search_data);
while((node=pbvh_iter_next(&iter)))
if(node->flag & PBVH_Leaf)
if (node->flag & PBVH_Leaf)
hcb(node, hit_data);
pbvh_iter_end(&iter);
}
typedef struct node_tree {
PBVHNode* data;
struct node_tree* left;
struct node_tree* right;
} node_tree;
static void node_tree_insert(node_tree* tree, node_tree* new_node)
{
if (new_node->data->tmin < tree->data->tmin) {
if (tree->left) {
node_tree_insert(tree->left, new_node);
}
else {
tree->left = new_node;
}
}
else {
if (tree->right) {
node_tree_insert(tree->right, new_node);
}
else {
tree->right = new_node;
}
}
}
static void traverse_tree(node_tree* tree, BLI_pbvh_HitOccludedCallback hcb, void* hit_data, float* tmin)
{
if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin);
hcb(tree->data, hit_data, tmin);
if (tree->right) traverse_tree(tree->right, hcb, hit_data, tmin);
}
static void free_tree(node_tree* tree)
{
if (tree->left) {
free_tree(tree->left);
tree->left = 0;
}
if (tree->right) {
free_tree(tree->right);
tree->right = 0;
}
free(tree);
}
float BLI_pbvh_node_get_tmin(PBVHNode* node)
{
return node->tmin;
}
void BLI_pbvh_search_callback_occluded(PBVH *bvh,
BLI_pbvh_SearchCallback scb, void *search_data,
BLI_pbvh_HitOccludedCallback hcb, void *hit_data)
{
PBVHIter iter;
PBVHNode *node;
node_tree *tree = 0;
pbvh_iter_begin(&iter, bvh, scb, search_data);
while((node=pbvh_iter_next_occluded(&iter))) {
if(node->flag & PBVH_Leaf) {
node_tree* new_node = malloc(sizeof(node_tree));
new_node->data = node;
new_node->left = NULL;
new_node->right = NULL;
if (tree) {
node_tree_insert(tree, new_node);
}
else {
tree = new_node;
}
}
}
pbvh_iter_end(&iter);
if (tree) {
float tmin = FLT_MAX;
traverse_tree(tree, hcb, hit_data, &tmin);
free_tree(tree);
}
}
static int update_search_cb(PBVHNode *node, void *data_v)
{
int flag= GET_INT_FROM_POINTER(data_v);
@@ -985,7 +1118,8 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
GHashIterator *hiter;
GHash *map;
void *face, **faces;
int i, tot;
unsigned i;
int tot;
map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "pbvh_get_grid_updates gh");
@@ -1086,6 +1220,18 @@ void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
copy_v3_v3(bb_max, node->orig_vb.bmax);
}
void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count)
{
if (node->proxy_count > 0) {
if (proxies) *proxies = node->proxies;
if (proxy_count) *proxy_count = node->proxy_count;
}
else {
if (proxies) *proxies = 0;
if (proxy_count) *proxy_count = 0;
}
}
/********************************* Raycast ***********************************/
typedef struct {
@@ -1100,16 +1246,13 @@ typedef struct {
static int ray_aabb_intersect(PBVHNode *node, void *data_v)
{
RaycastData *ray = data_v;
float bb_min[3], bb_max[3], bbox[2][3];
float bbox[2][3];
float tmin, tmax, tymin, tymax, tzmin, tzmax;
if(ray->original)
BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
BLI_pbvh_node_get_original_BB(node, bbox[0], bbox[1]);
else
BLI_pbvh_node_get_BB(node, bb_min, bb_max);
copy_v3_v3(bbox[0], bb_min);
copy_v3_v3(bbox[1], bb_max);
BLI_pbvh_node_get_BB(node, bbox[0], bbox[1]);
tmin = (bbox[ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
tmax = (bbox[1-ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
@@ -1119,8 +1262,10 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v)
if((tmin > tymax) || (tymin > tmax))
return 0;
if(tymin > tmin)
tmin = tymin;
if(tymax < tmax)
tmax = tymax;
@@ -1129,20 +1274,20 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v)
if((tmin > tzmax) || (tzmin > tmax))
return 0;
if(tzmin > tmin)
tmin = tzmin;
// XXX jwilkins: tmax does not need to be updated since we don't use it
// keeping this here for future reference
//if(tzmax < tmax) tmax = tzmax;
node->tmin = tmin;
return 1;
/* XXX: Not sure about this?
if(tzmin > tmin)
tmin = tzmin;
if(tzmax < tmax)
tmax = tzmax;
return ((tmin < t1) && (tmax > t0));
*/
}
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original)
{
RaycastData rcd;
@@ -1156,37 +1301,24 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
rcd.sign[2] = rcd.inv_dir[2] < 0;
rcd.original = original;
BLI_pbvh_search_callback(bvh, ray_aabb_intersect, &rcd, cb, data);
BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
}
/* XXX: Code largely copied from bvhutils.c, could be unified */
/* Returns 1 if a better intersection has been found */
static int ray_face_intersection(float ray_start[3], float ray_normal[3],
float *t0, float *t1, float *t2, float *t3,
float *fdist)
{
int hit = 0;
float dist;
do
{
float dist = FLT_MAX;
if(!isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2,
&dist, NULL, 0.1f))
dist = FLT_MAX;
if(dist >= 0 && dist < *fdist) {
hit = 1;
*fdist = dist;
}
t1 = t2;
t2 = t3;
t3 = NULL;
} while(t2);
return hit;
if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist, NULL, 0.1f) && dist < *fdist) ||
(t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist))
{
*fdist = dist;
return 1;
}
else {
return 0;
}
}
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
@@ -1399,3 +1531,86 @@ int BLI_pbvh_isDeformed(PBVH *pbvh)
{
return pbvh->deformed;
}
/* Proxies */
PBVHProxyNode* BLI_pbvh_node_add_proxy(PBVH* bvh, PBVHNode* node)
{
int index, totverts;
#pragma omp critical
{
index = node->proxy_count;
node->proxy_count++;
if (node->proxies)
node->proxies= MEM_reallocN(node->proxies, node->proxy_count*sizeof(PBVHProxyNode));
else
node->proxies= MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
if (bvh->grids)
totverts = node->totprim*bvh->gridsize*bvh->gridsize;
else
totverts = node->uniq_verts;
node->proxies[index].co= MEM_callocN(sizeof(float[3])*totverts, "PBVHNodeProxy.co");
}
return node->proxies + index;
}
void BLI_pbvh_node_free_proxies(PBVHNode* node)
{
#pragma omp critical
{
int p;
for (p= 0; p < node->proxy_count; p++) {
MEM_freeN(node->proxies[p].co);
node->proxies[p].co= 0;
}
MEM_freeN(node->proxies);
node->proxies = 0;
node->proxy_count= 0;
}
}
void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** r_array, int* r_tot)
{
PBVHNode **array= NULL, **newarray, *node;
int tot= 0, space= 0;
int n;
for (n= 0; n < pbvh->totnode; n++) {
node = pbvh->nodes + n;
if(node->proxy_count > 0) {
if(tot == space) {
/* resize array if needed */
space= (tot == 0)? 32: space*2;
newarray= MEM_callocN(sizeof(PBVHNode)*space, "BLI_pbvh_gather_proxies");
if (array) {
memcpy(newarray, array, sizeof(PBVHNode)*tot);
MEM_freeN(array);
}
array= newarray;
}
array[tot]= node;
tot++;
}
}
if(tot == 0 && array) {
MEM_freeN(array);
array= NULL;
}
*r_array= array;
*r_tot= tot;
}

View File

@@ -1539,6 +1539,7 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->id.flag -= LIB_NEEDLINK;
brush->mtex.tex= newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->image_icon= newlibadr_us(fd, brush->id.lib, brush->image_icon);
brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
}
}
@@ -10971,6 +10972,82 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
{
/* GSOC 2010 Sculpt - New settings for Brush */
Brush *brush;
for (brush= main->brush.first; brush; brush= brush->id.next) {
/* Sanity Check */
// infinite number of dabs
if (brush->spacing == 0)
brush->spacing = 10;
// will have no effect
if (brush->alpha == 0)
brush->alpha = 0.5f;
// bad radius
if (brush->unprojected_radius == 0)
brush->unprojected_radius = 0.125;
// unusable size
if (brush->size == 0)
brush->size = 35;
// can't see overlay
if (brush->texture_overlay_alpha == 0)
brush->texture_overlay_alpha = 33;
// same as draw brush
if (brush->crease_pinch_factor == 0)
brush->crease_pinch_factor = 0.5f;
// will sculpt no vertexes
if (brush->plane_trim == 0)
brush->plane_trim = 0.5f;
// same as smooth stroke off
if (brush->smooth_stroke_radius == 0)
brush->smooth_stroke_radius= 75;
// will keep cursor in one spot
if (brush->smooth_stroke_radius == 1)
brush->smooth_stroke_factor= 0.9f;
// same as dots
if (brush->rate == 0)
brush->rate = 0.1f;
/* New Settings */
if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 6)) {
brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space
// spacing was originally in pixels, convert it to percentage for new version
// size should not be zero due to sanity check above
brush->spacing = (int)(100*((float)brush->spacing) / ((float)brush->size));
if (brush->add_col[0] == 0 &&
brush->add_col[1] == 0 &&
brush->add_col[2] == 0)
{
brush->add_col[0] = 1.00;
brush->add_col[1] = 0.39;
brush->add_col[2] = 0.39;
}
if (brush->sub_col[0] == 0 &&
brush->sub_col[1] == 0 &&
brush->sub_col[2] == 0)
{
brush->sub_col[0] = 0.39;
brush->sub_col[1] = 0.39;
brush->sub_col[2] = 1.00;
}
}
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */

View File

@@ -243,7 +243,7 @@ static void draw_gpencil_panel (bContext *C, uiLayout *layout, bGPdata *gpd, Poi
col= uiLayoutColumn(layout, 0);
/* current Grease Pencil block */
// TODO: show some info about who owns this?
uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink");
uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink", NULL);
/* add new layer button - can be used even when no data, since it can add a new block too */
uiItemO(col, NULL, 0, "GPENCIL_OT_layer_add");

View File

@@ -669,11 +669,11 @@ uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout);
void uiTemplateHeader(uiLayout *layout, struct bContext *C, int menus);
void uiTemplateDopeSheetFilter(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *newop, char *openop, char *unlinkop);
char *newop, char *openop, char *unlinkop, char *filterop);
void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *newop, char *openop, char *unlinkop);
char *newop, char *openop, char *unlinkop, char *filterop);
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *newop, char *openop, char *unlinkop, int rows, int cols);
char *newop, char *openop, char *unlinkop, char *filterop, int rows, int cols);
void uiTemplateAnyID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *proptypename, char *text);
void uiTemplatePathBuilder(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,

View File

@@ -46,6 +46,7 @@
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "DNA_brush_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -762,6 +763,7 @@ static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel)
prv_img->w[miplevel] = size;
prv_img->h[miplevel] = size;
prv_img->changed[miplevel] = 1;
prv_img->changed_timestamp[miplevel] = 0;
prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect");
}
}
@@ -976,6 +978,16 @@ int ui_id_icon_get(bContext *C, ID *id, int preview)
/* checks if not exists, or changed */
ui_id_icon_render(C, id, preview);
break;
case ID_BR:
{ /* use the image in the brush as the icon */
/* XXX redundancy here can be reduced be rewriting this switch as an if */
ID* ima_id = (ID*)((Brush*)id)->image_icon;
id = ima_id ? ima_id : id;
iconid= BKE_icon_getid(id);
/* checks if not exists, or changed */
ui_id_icon_render(C, id, preview);
}
break;
default:
break;
}

View File

@@ -42,6 +42,7 @@
#include "BKE_main.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_report.h"
#include "ED_screen.h"
#include "ED_render.h"
@@ -141,6 +142,8 @@ typedef struct TemplateID {
ListBase *idlb;
int prv_rows, prv_cols;
char filterop[64];
} TemplateID;
/* Search browse menu, assign */
@@ -170,15 +173,53 @@ static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSea
/* ID listbase */
for(id= lb->first; id; id= id->next) {
if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
int filter_yes;
/* hide dot-datablocks */
if(U.uiflag & USER_HIDE_DOT)
filter_yes= 0;
/* use filter */
if (template->filterop[0] != 0) {
PointerRNA ptr;
ReportList reports;
FunctionRNA *func;
ParameterList parms;
RNA_id_pointer_create(id, &ptr);
BKE_reports_init(&reports, RPT_PRINT);
func= RNA_struct_find_function(&ptr, template->filterop);
if (func) {
RNA_parameter_list_create(&parms, &ptr, func);
RNA_parameter_set_lookup(&parms, "context", &C);
if (RNA_function_call(C, &reports, &ptr, func, &parms) == 0) {
int* ret;
RNA_parameter_get_lookup(&parms, "ret", &ret);
if (!(*ret)) {
RNA_parameter_list_free(&parms);
continue;
}
else {
filter_yes= 1;
}
}
RNA_parameter_list_free(&parms);
}
}
/* hide dot-datablocks, but only if filter does not force it visible */
if(!filter_yes && U.uiflag & USER_HIDE_DOT)
if ((id->name[2]=='.') && (str[0] != '.'))
continue;
if(BLI_strcasestr(id->name+2, str)) {
iconid= ui_id_icon_get((bContext*)C, id, 1);
if(!uiSearchItemAdd(items, id->name+2, id, iconid))
break;
}
@@ -340,7 +381,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop, char *filterop)
{
uiBut *but;
uiBlock *block;
@@ -480,7 +521,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
uiBlockEndAlign(block);
}
static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int flag, int prv_rows, int prv_cols)
static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char* filterop, int flag, int prv_rows, int prv_cols)
{
TemplateID *template;
PropertyRNA *prop;
@@ -498,7 +539,12 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char
template->prop= prop;
template->prv_rows = prv_rows;
template->prv_cols = prv_cols;
if (filterop)
BLI_strncpy(template->filterop, filterop, sizeof(template->filterop));
else
template->filterop[0] = 0;
if(newop)
flag |= UI_ID_ADD_NEW;
if(openop)
@@ -512,26 +558,25 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char
*/
if(template->idlb) {
uiLayoutRow(layout, 1);
template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
template_ID(C, layout, template, type, flag, newop, openop, unlinkop, filterop);
}
MEM_freeN(template);
}
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
}
void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
}
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop, int rows, int cols)
{
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
}
/************************ ID Chooser Template ***************************/

View File

@@ -1463,7 +1463,7 @@ void init_userdef_do_versions(void)
SETCOL(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
}
}
if (G.main->versionfile <= 252 || (G.main->versionfile == 252 && G.main->subversionfile < 5)) {
if (G.main->versionfile < 252 || (G.main->versionfile == 252 && G.main->subversionfile < 5)) {
bTheme *btheme;
/* interface_widgets.c */
@@ -1521,7 +1521,14 @@ void init_userdef_do_versions(void)
/* this timer uses U */
// XXX reset_autosave();
/* GSOC Sculpt 2010 - Sanity check on Sculpt/Paint settings */
if (U.sculpt_paint_unified_alpha == 0)
U.sculpt_paint_unified_alpha = 0.5f;
if (U.sculpt_paint_unified_unprojected_radius == 0)
U.sculpt_paint_unified_unprojected_radius = 0.125f;
if (U.sculpt_paint_unified_size == 0)
U.sculpt_paint_unified_size = 35;
}

View File

@@ -3,6 +3,8 @@ Import ('env')
sources = env.Glob('*.c')
defs = []
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
@@ -12,7 +14,11 @@ if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
if env['OURPLATFORM'] == 'linuxcross':
if env['WITH_BF_OPENMP']:
incs += ' ' + env['BF_OPENMP_INC']
env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), [], libtype=['core'], priority=[40] )
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] )

View File

@@ -641,8 +641,8 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
}
}
else {
xi = (uv[0]*ibuf->x) + 0.5f;
yi = (uv[1]*ibuf->y) + 0.5f;
xi = (int)((uv[0]*ibuf->x) + 0.5f);
yi = (int)((uv[1]*ibuf->y) + 0.5f);
//if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0;
@@ -1053,15 +1053,15 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
* This is incorrect. Its already given radians but without it wont work.
* need to look into a fix - campbell */
if (is_quad) {
a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * (M_PI/180.0f));
a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * (M_PI/180.0f));
a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI/180.0f));
a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI/180.0f));
}
else {
a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * (M_PI/180.0f));
a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI/180.0f));
a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
}
if (is_quad) {
@@ -1197,7 +1197,7 @@ static void screen_px_from_persp(
w[2] *= wtot_inv;
}
else {
w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */
}
/* done re-weighting */
@@ -2513,11 +2513,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
w[0]=w[1]=w[2]= 0.0;
if (side) {
w[fidx1?fidx1-1:0] = fac;
w[fidx2?fidx2-1:0] = 1.0-fac;
w[fidx2?fidx2-1:0] = 1.0f-fac;
}
else {
w[fidx1] = fac;
w[fidx2] = 1.0-fac;
w[fidx2] = 1.0f-fac;
}
#endif
}
@@ -2571,11 +2571,12 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
{
/* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
bucketMin[0] = (int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
bucketMin[1] = (int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f;
/* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */
bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */
bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
bucketMax[0] = (int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f;
bucketMax[1] = (int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f;
bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
/* incase the rect is outside the mesh 2d bounds */
CLAMP(bucketMin[0], 0, ps->buckets_x);
@@ -3029,19 +3030,19 @@ static void project_paint_begin(ProjPaintState *ps)
if(ps->source==PROJ_SRC_VIEW) {
#ifdef PROJ_DEBUG_WINCLIP
CLAMP(ps->screenMin[0], -ps->brush->size, ps->winx + ps->brush->size);
CLAMP(ps->screenMax[0], -ps->brush->size, ps->winx + ps->brush->size);
CLAMP(ps->screenMin[0], (float)(-ps->brush->size), (float)(ps->winx + ps->brush->size));
CLAMP(ps->screenMax[0], (float)(-ps->brush->size), (float)(ps->winx + ps->brush->size));
CLAMP(ps->screenMin[1], -ps->brush->size, ps->winy + ps->brush->size);
CLAMP(ps->screenMax[1], -ps->brush->size, ps->winy + ps->brush->size);
CLAMP(ps->screenMin[1], (float)(-ps->brush->size), (float)(ps->winy + ps->brush->size));
CLAMP(ps->screenMax[1], (float)(-ps->brush->size), (float)(ps->winy + ps->brush->size));
#endif
}
else { /* reprojection, use bounds */
ps->screenMin[0]= 0;
ps->screenMax[0]= ps->winx;
ps->screenMax[0]= (float)(ps->winx);
ps->screenMin[1]= 0;
ps->screenMax[1]= ps->winy;
ps->screenMax[1]= (float)(ps->winy);
}
/* only for convenience */
@@ -3497,7 +3498,7 @@ static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf
project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
if ( (ps->source != PROJ_SRC_VIEW) ||
project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)
project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, (float)(ps->brush->size * ps->brush->size), bucket_bounds)
) {
*bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
ps->context_bucket_x++;
@@ -3545,7 +3546,7 @@ static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const u
static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac)
{
const float mfac= 1.0-fac;
const float mfac= 1.0f-fac;
cp[0]= mfac*cp1[0] + fac*cp2[0];
cp[1]= mfac*cp1[1] + fac*cp2[1];
cp[2]= mfac*cp1[2] + fac*cp2[2];
@@ -3712,7 +3713,7 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* avoid a square root with every dist comparison */
brush_size_sqared = ps->brush->size * ps->brush->size;
brush_size_sqared = (float)(ps->brush->size * ps->brush->size);
/* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
@@ -3771,7 +3772,7 @@ static void *do_projectpaint_thread(void *ph_v)
falloff = 1.0f - falloff;
falloff = 1.0f - (falloff * falloff);
mask_short = projPixel->mask * (ps->brush->alpha * falloff);
mask_short = (unsigned short)(projPixel->mask * (ps->brush->alpha * falloff));
if (mask_short > projPixel->mask_max) {
mask = ((float)mask_short)/65535.0f;
projPixel->mask_max = mask_short;
@@ -3932,8 +3933,8 @@ static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, i
/* Use mouse coords as floats for projection painting */
float pos[2];
pos[0] = mval_i[0];
pos[1] = mval_i[1];
pos[0] = (float)(mval_i[0]);
pos[1] = (float)(mval_i[1]);
// we may want to use this later
// brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0);
@@ -4057,7 +4058,8 @@ static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
{
float inrgb[3];
if ((x >= ibuf->x) || (y >= ibuf->y)) {
// XXX: signed unsigned mismatch
if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb);
else return 0;
}
@@ -4611,8 +4613,8 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
ps->normal_angle_inner= ps->normal_angle= settings->imapaint.normal_angle;
}
ps->normal_angle_inner *= M_PI_2 / 90;
ps->normal_angle *= M_PI_2 / 90;
ps->normal_angle_inner *= (float)(M_PI_2 / 90);
ps->normal_angle *= (float)(M_PI_2 / 90);
ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
if(ps->normal_angle_range <= 0.0f)
@@ -4711,8 +4713,8 @@ static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
int mouse[2], redraw;
RNA_float_get_array(itemptr, "mouse", mousef);
mouse[0] = mousef[0];
mouse[1] = mousef[1];
mouse[0] = (int)(mousef[0]);
mouse[1] = (int)(mousef[1]);
time= RNA_float_get(itemptr, "time");
pressure= RNA_float_get(itemptr, "pressure");
@@ -4832,8 +4834,8 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
/* fill in stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
mousef[0] = mouse[0];
mousef[1] = mouse[1];
mousef[0] = (float)(mouse[0]);
mousef[1] = (float)(mouse[1]);
RNA_float_set_array(&itemptr, "mouse", mousef);
RNA_float_set(&itemptr, "time", (float)(time - pop->starttime));
RNA_float_set(&itemptr, "pressure", pressure);
@@ -4950,7 +4952,7 @@ static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
glColor4ub(255, 255, 255, 128);
glEnable( GL_LINE_SMOOTH );
glEnable(GL_BLEND);
glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size*0.5f, 40);
glutil_draw_lined_arc(0, (float)(M_PI*2.0), brush->size*0.5f, 40);
glDisable(GL_BLEND);
glDisable( GL_LINE_SMOOTH );
@@ -4977,7 +4979,7 @@ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *eve
ToolSettings *ts = CTX_data_scene(C)->toolsettings;
get_imapaint_zoom(C, &zoom, &zoom);
toggle_paint_cursor(C, !ts->imapaint.paintcursor);
brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5 * zoom);
brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5f * zoom);
return WM_radial_control_invoke(C, op, event);
}
@@ -4997,7 +4999,7 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op)
int ret;
char str[256];
get_imapaint_zoom(C, &zoom, &zoom);
ret = brush_radial_control_exec(op, brush, 2.0 / zoom);
ret = brush_radial_control_exec(op, brush, 2.0f / zoom);
WM_radial_control_string(op, str, 256);
WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);

View File

@@ -110,6 +110,13 @@ void PAINT_OT_face_select_all(struct wmOperatorType *ot);
int facemask_paint_poll(struct bContext *C);
/* stroke operator */
typedef enum wmBrushStrokeMode {
WM_BRUSHSTROKE_NORMAL,
WM_BRUSHSTROKE_INVERT,
WM_BRUSHSTROKE_SMOOTH,
} wmBrushStrokeMode;
/* paint_undo.c */
typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
typedef void (*UndoFreeCb)(struct ListBase *lb);

View File

@@ -39,28 +39,25 @@
#include "sculpt_intern.h"
#include <string.h>
//#include <stdio.h>
/* Brush operators */
static int brush_add_exec(bContext *C, wmOperator *op)
{
/*int type = RNA_enum_get(op->ptr, "type");*/
Brush *br = NULL;
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *br = paint_brush(paint);
br = add_brush("Brush");
if (br)
br = copy_brush(br);
else
br = add_brush("Brush");
if(br)
paint_brush_set(paint_get_active(CTX_data_scene(C)), br);
paint_brush_set(paint_get_active(CTX_data_scene(C)), br);
return OPERATOR_FINISHED;
}
static EnumPropertyItem brush_type_items[] = {
{OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt", ""},
{OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{0, NULL, 0, NULL, NULL}};
void BRUSH_OT_add(wmOperatorType *ot)
{
/* identifiers */
@@ -72,9 +69,43 @@ void BRUSH_OT_add(wmOperatorType *ot)
ot->exec= brush_add_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
ot->flag= OPTYPE_UNDO;
}
RNA_def_enum(ot->srna, "type", brush_type_items, OB_MODE_VERTEX_PAINT, "Type", "Which paint mode to create the brush for.");
static int brush_scale_size_exec(bContext *C, wmOperator *op)
{
/*int type = RNA_enum_get(op->ptr, "type");*/
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *br = paint_brush(paint);
float factor = RNA_float_get(op->ptr, "scalar");
if (br) {
if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) {
U.sculpt_paint_unified_size *= factor;
}
else {
br->size *= factor;
}
}
return OPERATOR_FINISHED;
}
void BRUSH_OT_scale_size(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Scale Sculpt/Paint Brush Size";
ot->description= "Change brush size by a scalar";
ot->idname= "BRUSH_OT_scale_size";
/* api callbacks */
ot->exec= brush_scale_size_exec;
/* flags */
ot->flag= OPTYPE_UNDO;
RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
}
static int vertex_color_set_exec(bContext *C, wmOperator *op)
@@ -108,8 +139,10 @@ void ED_operatortypes_paint(void)
{
/* brush */
WM_operatortype_append(BRUSH_OT_add);
WM_operatortype_append(BRUSH_OT_scale_size);
WM_operatortype_append(BRUSH_OT_curve_preset);
/* image */
WM_operatortype_append(PAINT_OT_texture_paint_toggle);
WM_operatortype_append(PAINT_OT_texture_paint_radial_control);
@@ -141,6 +174,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_all);
}
static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *path)
{
wmKeyMapItem *kmi;
@@ -180,15 +214,13 @@ static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *path)
static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *path)
{
wmKeyMapItem *kmi;
kmi= WM_keymap_add_item(keymap, "WM_OT_context_scale_int", LEFTBRACKETKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", path);
RNA_float_set(kmi->ptr, "value", 0.9);
kmi= WM_keymap_add_item(keymap, "WM_OT_context_scale_int", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", path);
RNA_float_set(kmi->ptr, "value", 10.0/9.0); // 1.1111....
}
kmi= WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", LEFTBRACKETKEY, KM_PRESS, 0, 0);
RNA_float_set(kmi->ptr, "scalar", 0.9);
kmi= WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
RNA_float_set(kmi->ptr, "scalar", 10.0/9.0); // 1.1111....
}
void ED_keymap_paint(wmKeyConfig *keyconf)
{
@@ -200,12 +232,15 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap= WM_keymap_find(keyconf, "Sculpt", 0, 0);
keymap->poll= sculpt_poll;
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE);
WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", WM_BRUSHSTROKE_NORMAL);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_BRUSHSTROKE_INVERT);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_BRUSHSTROKE_SMOOTH);
//stroke_mode_modal_keymap(keyconf);
for(i=0; i<=5; i++)
RNA_int_set(WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY+i, KM_PRESS, KM_CTRL, 0)->ptr, "level", i);
@@ -221,7 +256,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "tool_settings.sculpt.active_brush_index");
ed_keymap_paint_brush_size(keymap, "tool_settings.sculpt.brush.size");
/* */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", AKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.use_anchor");
@@ -254,11 +290,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", LKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.active_brush_name");
RNA_string_set(kmi->ptr, "value", "Layer");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", TKEY, KM_PRESS, KM_SHIFT, 0); // was just T in 2.4x
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.active_brush_name");
RNA_string_set(kmi->ptr, "value", "Flatten");
/* Vertex Paint mode */
keymap= WM_keymap_find(keyconf, "Vertex Paint", 0, 0);

View File

@@ -20,7 +20,7 @@
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
* Contributor(s): Jason Wilkins, Tom Musgrove.
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_brush.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -49,6 +50,9 @@
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h" // XXX, for expedience in getting this working, refactor later (or this just shows that this needs unification)
#include "BKE_image.h"
#include <float.h>
#include <math.h>
@@ -96,54 +100,748 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
glDisable(GL_LINE_SMOOTH);
}
static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
#if 0
// grid texture for testing
#define GRID_WIDTH 8
#define GRID_LENGTH 8
#define W (0xFFFFFFFF)
#define G (0x00888888)
#define E (0xE1E1E1E1)
#define C (0xC3C3C3C3)
#define O (0xB4B4B4B4)
#define Q (0xA9A9A9A9)
static unsigned grid_texture0[256] =
{
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
};
if(!(paint->flags & PAINT_SHOW_BRUSH))
return;
static unsigned grid_texture1[64] =
{
C,C,C,C,C,C,C,C,
C,G,G,G,G,G,G,C,
C,G,G,G,G,G,G,C,
C,G,G,G,G,G,G,C,
C,G,G,G,G,G,G,C,
C,G,G,G,G,G,G,C,
C,G,G,G,G,G,G,C,
C,C,C,C,C,C,C,C,
};
glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
static unsigned grid_texture2[16] =
{
O,O,O,O,
O,G,G,O,
O,G,G,O,
O,O,O,O,
};
glTranslatef((float)x, (float)y, 0.0f);
glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
glTranslatef((float)-x, (float)-y, 0.0f);
static unsigned grid_texture3[4] =
{
Q,Q,
Q,Q,
};
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
static unsigned grid_texture4[1] =
{
Q,
};
#undef W
#undef G
#undef E
#undef C
#undef O
#undef Q
static void load_grid()
{
static GLuint overlay_texture;
if (!overlay_texture) {
//GLfloat largest_supported_anisotropy;
glGenTextures(1, &overlay_texture);
glBindTexture(GL_TEXTURE_2D, overlay_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture0);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture1);
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture2);
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGB, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture3);
glTexImage2D(GL_TEXTURE_2D, 4, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture4);
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
//glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
}
}
#endif
extern float get_tex_pixel(Brush* br, float u, float v);
typedef struct Snapshot {
float size[3];
float ofs[3];
float rot;
int brush_size;
int winx;
int winy;
int brush_map_mode;
int curve_changed_timestamp;
} Snapshot;
static int same_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
{
MTex* mtex = &brush->mtex;
return
(mtex->tex &&
mtex->ofs[0] == snap->ofs[0] &&
mtex->ofs[1] == snap->ofs[1] &&
mtex->ofs[2] == snap->ofs[2] &&
mtex->size[0] == snap->size[0] &&
mtex->size[1] == snap->size[1] &&
mtex->size[2] == snap->size[2] &&
mtex->rot == snap->rot) &&
((mtex->brush_map_mode == MTEX_MAP_MODE_FIXED && sculpt_get_brush_size(brush) <= snap->brush_size) || (sculpt_get_brush_size(brush) == snap->brush_size)) && // make brush smaller shouldn't cause a resample
mtex->brush_map_mode == snap->brush_map_mode &&
vc->ar->winx == snap->winx &&
vc->ar->winy == snap->winy;
}
static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
{
if (brush->mtex.tex) {
snap->brush_map_mode = brush->mtex.brush_map_mode;
copy_v3_v3(snap->ofs, brush->mtex.ofs);
copy_v3_v3(snap->size, brush->mtex.size);
snap->rot = brush->mtex.rot;
}
else {
snap->brush_map_mode = -1;
snap->ofs[0]= snap->ofs[0]= snap->ofs[0]= -1;
snap->size[0]= snap->size[0]= snap->size[0]= -1;
snap->rot = -1;
}
snap->brush_size = sculpt_get_brush_size(brush);
snap->winx = vc->ar->winx;
snap->winy = vc->ar->winy;
}
int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
{
static GLuint overlay_texture = 0;
static int init = 0;
static int tex_changed_timestamp = -1;
static int curve_changed_timestamp = -1;
static Snapshot snap;
static int old_size = -1;
GLubyte* buffer = 0;
int size;
int j;
int refresh;
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED && !br->mtex.tex) return 0;
refresh =
!overlay_texture ||
(br->mtex.tex &&
(!br->mtex.tex->preview ||
br->mtex.tex->preview->changed_timestamp[0] != tex_changed_timestamp)) ||
!br->curve ||
br->curve->changed_timestamp != curve_changed_timestamp ||
!same_snap(&snap, br, vc);
if (refresh) {
if (br->mtex.tex && br->mtex.tex->preview)
tex_changed_timestamp = br->mtex.tex->preview->changed_timestamp[0];
if (br->curve)
curve_changed_timestamp = br->curve->changed_timestamp;
make_snap(&snap, br, vc);
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
int s = sculpt_get_brush_size(br);
int r = 1;
for (s >>= 1; s > 0; s >>= 1)
r++;
size = (1<<r);
if (size < 256)
size = 256;
if (size < old_size)
size = old_size;
}
else
size = 512;
if (old_size != size) {
if (overlay_texture) {
glDeleteTextures(1, &overlay_texture);
overlay_texture = 0;
}
init = 0;
old_size = size;
}
buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex");
#pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP)
for (j= 0; j < size; j++) {
int i;
float y;
float len;
for (i= 0; i < size; i++) {
// largely duplicated from tex_strength
const float rotation = -br->mtex.rot;
float diameter = sculpt_get_brush_size(br);
int index = j*size + i;
float x;
float avg;
x = (float)i/size;
y = (float)j/size;
x -= 0.5f;
y -= 0.5f;
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
x *= vc->ar->winx / diameter;
y *= vc->ar->winy / diameter;
}
else {
x *= 2;
y *= 2;
}
len = sqrtf(x*x + y*y);
if ((br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) || len <= 1) {
/* it is probably worth optimizing for those cases where
the texture is not rotated by skipping the calls to
atan2, sqrtf, sin, and cos. */
if (br->mtex.tex && (rotation > 0.001 || rotation < -0.001)) {
const float angle = atan2(y, x) + rotation;
x = len * cos(angle);
y = len * sin(angle);
}
x *= br->mtex.size[0];
y *= br->mtex.size[1];
x += br->mtex.ofs[0];
y += br->mtex.ofs[1];
avg = br->mtex.tex ? get_tex_pixel(br, x, y) : 1;
avg += br->texture_sample_bias;
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED)
avg *= brush_curve_strength(br, len, 1); /* Falloff curve */
buffer[index] = (GLubyte)(255*avg);
}
else {
buffer[index] = 0;
}
}
}
if (!overlay_texture)
glGenTextures(1, &overlay_texture);
}
else {
size= old_size;
}
glBindTexture(GL_TEXTURE_2D, overlay_texture);
if (refresh) {
if (!init) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
init = 1;
}
else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
}
if (buffer)
MEM_freeN(buffer);
}
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}
return 1;
}
/* Convert a point in model coordinates to 2D screen coordinates. */
// XXX duplicated from sculpt.c, deal with this later.
static void projectf(bglMats *mats, const float v[3], float p[2])
{
double ux, uy, uz;
gluProject(v[0],v[1],v[2], mats->modelview, mats->projection,
(GLint *)mats->viewport, &ux, &uy, &uz);
p[0]= ux;
p[1]= uy;
}
static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
{
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
viewvector(rv3d, location, view);
// create a vector that is not orthogonal to view
if (fabsf(view[0]) < 0.1) {
nonortho[0] = view[0] + 1;
nonortho[1] = view[1];
nonortho[2] = view[2];
}
else if (fabsf(view[1]) < 0.1) {
nonortho[0] = view[0];
nonortho[1] = view[1] + 1;
nonortho[2] = view[2];
}
else {
nonortho[0] = view[0];
nonortho[1] = view[1];
nonortho[2] = view[2] + 1;
}
// get a vector in the plane of the view
cross_v3_v3v3(ortho, nonortho, view);
normalize_v3(ortho);
// make a point on the surface of the brush tagent to the view
mul_v3_fl(ortho, radius);
add_v3_v3v3(offset, location, ortho);
// project the center of the brush, and the tagent point to the view onto the screen
projectf(mats, location, p1);
projectf(mats, offset, p2);
// the distance between these points is the size of the projected brush in pixels
return len_v2v2(p1, p2);
}
int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4])
{
struct PaintStroke *stroke;
float window[2];
int hit;
stroke = paint_stroke_new(C, NULL, NULL, NULL, NULL);
window[0] = x + stroke->vc.ar->winrct.xmin;
window[1] = y + stroke->vc.ar->winrct.ymin;
memcpy(modelview, stroke->vc.rv3d->viewmat, sizeof(float[16]));
memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16]));
memcpy(viewport, stroke->mats.viewport, sizeof(int[4]));
if (stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
*pixel_radius = project_brush_radius(stroke->vc.rv3d, sculpt_get_brush_unprojected_radius(stroke->brush), location, &stroke->mats);
if (*pixel_radius == 0)
*pixel_radius = sculpt_get_brush_size(stroke->brush);
mul_m4_v3(stroke->vc.obact->sculpt->ob->obmat, location);
hit = 1;
}
else {
Sculpt* sd = CTX_data_tool_settings(C)->sculpt;
Brush* brush = paint_brush(&sd->paint);
*pixel_radius = sculpt_get_brush_size(brush);
hit = 0;
}
paint_stroke_free(stroke);
return hit;
}
// XXX duplicated from sculpt.c
float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset)
{
float delta[3], scale, loc[3];
mul_v3_m4v3(loc, ob->obmat, center);
initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
window_to_3d_delta(vc->ar, delta, offset, 0);
scale= fabsf(mat4_to_scale(ob->obmat));
scale= (scale == 0.0f)? 1.0f: scale;
return len_v3(delta)/scale;
}
// XXX paint cursor now does a lot of the same work that is needed during a sculpt stroke
// problem: all this stuff was not intended to be used at this point, so things feel a
// bit hacked. I've put lots of stuff in Brush that probably better goes in Paint
// Functions should be refactored so that they can be used between sculpt.c and
// paint_stroke.c clearly and optimally and the lines of communication between the
// two modules should be more clearly defined.
static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
{
ViewContext vc;
(void)unused;
view3d_set_viewcontext(C, &vc);
if (vc.obact->sculpt) {
Paint *paint = paint_get_active(CTX_data_scene(C));
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = paint_brush(paint);
int pixel_radius, viewport[4];
float location[3], modelview[16], projection[16];
int hit;
int flip;
int sign;
float* col;
float alpha;
float visual_strength = sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush);
const float min_alpha = 0.20f;
const float max_alpha = 0.80f;
{
const float u = 0.5f;
const float v = 1 - u;
const float r = 20;
const float dx = sd->last_x - x;
const float dy = sd->last_y - y;
if (dx*dx + dy*dy >= r*r) {
sd->last_angle = atan2(dx, dy);
sd->last_x = u*sd->last_x + v*x;
sd->last_y = u*sd->last_y + v*y;
}
}
if(!sculpt_get_lock_brush_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH))
return;
hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
if (sculpt_get_lock_brush_size(brush))
sculpt_set_brush_size(brush, pixel_radius);
// XXX: no way currently to know state of pen flip or invert key modifier without starting a stroke
flip = 1;
sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1);
if (sign < 0 && ELEM4(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH))
col = brush->sub_col;
else
col = brush->add_col;
alpha = (paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f;
if (ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED) && brush->flag & BRUSH_TEXTURE_OVERLAY) {
glPushAttrib(
GL_COLOR_BUFFER_BIT|
GL_CURRENT_BIT|
GL_DEPTH_BUFFER_BIT|
GL_ENABLE_BIT|
GL_LINE_BIT|
GL_POLYGON_BIT|
GL_STENCIL_BUFFER_BIT|
GL_TRANSFORM_BIT|
GL_VIEWPORT_BIT|
GL_TEXTURE_BIT);
if (load_tex(sd, brush, &vc)) {
glEnable(GL_BLEND);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_FALSE);
glDepthFunc(GL_ALWAYS);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
glTranslatef(0.5f, 0.5f, 0);
if (brush->flag & BRUSH_RAKE) {
glRotatef(sd->last_angle*(float)(180.0/M_PI), 0, 0, 1);
}
else {
glRotatef(sd->special_rotation*(float)(180.0/M_PI), 0, 0, 1);
}
glTranslatef(-0.5f, -0.5f, 0);
if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE)) {
glTranslatef(0.5f, 0.5f, 0);
glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1);
glTranslatef(-0.5f, -0.5f, 0);
}
}
glColor4f(
U.sculpt_paint_overlay_col[0],
U.sculpt_paint_overlay_col[1],
U.sculpt_paint_overlay_col[2],
brush->texture_overlay_alpha / 100.0f);
glBegin(GL_QUADS);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
if (sd->draw_anchored) {
glTexCoord2f(0, 0);
glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin);
glTexCoord2f(1, 0);
glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin);
glTexCoord2f(1, 1);
glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin);
glTexCoord2f(0, 1);
glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin);
}
else {
glTexCoord2f(0, 0);
glVertex2f((float)x-sculpt_get_brush_size(brush), (float)y-sculpt_get_brush_size(brush));
glTexCoord2f(1, 0);
glVertex2f((float)x+sculpt_get_brush_size(brush), (float)y-sculpt_get_brush_size(brush));
glTexCoord2f(1, 1);
glVertex2f((float)x+sculpt_get_brush_size(brush), (float)y+sculpt_get_brush_size(brush));
glTexCoord2f(0, 1);
glVertex2f((float)x-sculpt_get_brush_size(brush), (float)y+sculpt_get_brush_size(brush));
}
}
else {
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(viewport[2], 0);
glTexCoord2f(1, 1);
glVertex2f(viewport[2], viewport[3]);
glTexCoord2f(0, 1);
glVertex2f(0, viewport[3]);
}
glEnd();
glPopMatrix();
}
glPopAttrib();
}
if (hit) {
float unprojected_radius;
// XXX duplicated from brush_strength & paint_stroke_add_step, refactor later
//wmEvent* event = CTX_wm_window(C)->eventstate;
if (sd->draw_pressure && (brush->flag & BRUSH_ALPHA_PRESSURE))
visual_strength *= sd->pressure_value;
// don't show effect of strength past the soft limit
if (visual_strength > 1) visual_strength = 1;
if (sd->draw_anchored) {
unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, sd->anchored_size);
}
else {
if (brush->flag & BRUSH_ANCHORED)
unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, 8);
else
unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, sculpt_get_brush_size(brush));
}
if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE))
unprojected_radius *= sd->pressure_value;
if (!sculpt_get_lock_brush_size(brush))
sculpt_set_brush_unprojected_radius(brush, unprojected_radius);
if(!(paint->flags & PAINT_SHOW_BRUSH))
return;
}
glPushAttrib(
GL_COLOR_BUFFER_BIT|
GL_CURRENT_BIT|
GL_DEPTH_BUFFER_BIT|
GL_ENABLE_BIT|
GL_LINE_BIT|
GL_POLYGON_BIT|
GL_STENCIL_BUFFER_BIT|
GL_TRANSFORM_BIT|
GL_VIEWPORT_BIT|
GL_TEXTURE_BIT);
glColor4f(col[0], col[1], col[2], alpha);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
if (sd->draw_anchored) {
glTranslatef(sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin, 0.0f);
glutil_draw_lined_arc(0.0, M_PI*2.0, sd->anchored_size, 40);
glTranslatef(-sd->anchored_initial_mouse[0] + vc.ar->winrct.xmin, -sd->anchored_initial_mouse[1] + vc.ar->winrct.xmin, 0.0f);
}
else {
glTranslatef((float)x, (float)y, 0.0f);
glutil_draw_lined_arc(0.0, M_PI*2.0, sculpt_get_brush_size(brush), 40);
glTranslatef(-(float)x, -(float)y, 0.0f);
}
glPopAttrib();
}
else {
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
if(!(paint->flags & PAINT_SHOW_BRUSH))
return;
glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glTranslatef((float)x, (float)y, 0.0f);
glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40); // XXX: for now use the brushes size instead of potentially using the unified size because the feature has been enabled for sculpt
glTranslatef((float)-x, (float)-y, 0.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
{
Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX
Brush *brush = paint_brush(paint); // XXX
float mouse[2];
PointerRNA itemptr;
float pressure = 1;
float center[3] = {0, 0, 0};
int flip= event->shift?1:0;
float location[3];
float pressure;
int pen_flip;
ViewContext vc; // XXX
PaintStroke *stroke = op->customdata;
/* XXX: can remove the if statement once all modes have this */
if(stroke->get_location)
stroke->get_location(C, stroke, center, mouse);
view3d_set_viewcontext(C, &vc); // XXX
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
wmTabletData *wmtab= event->customdata;
if(wmtab->Active != EVT_TABLET_NONE)
pressure= wmtab->Pressure;
if(wmtab->Active == EVT_TABLET_ERASER)
flip = 1;
pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
pen_flip = (wmtab->Active == EVT_TABLET_ERASER);
}
else {
pressure = 1;
pen_flip = 0;
}
// XXX: temporary check for sculpt mode until things are more unified
if (vc.obact->sculpt) {
float delta[3];
brush_jitter_pos(brush, mouse_in, mouse);
// XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here
if (brush->flag & BRUSH_JITTER_PRESSURE) {
sub_v3_v3v3(delta, mouse, mouse_in);
mul_v3_fl(delta, pressure);
add_v3_v3v3(mouse, mouse_in, delta);
}
}
else
copy_v3_v3(mouse, mouse_in);
/* XXX: can remove the if statement once all modes have this */
if(stroke->get_location)
stroke->get_location(C, stroke, location, mouse);
else
zero_v3(location);
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
RNA_float_set_array(&itemptr, "location", center);
RNA_float_set_array(&itemptr, "mouse", mouse);
RNA_boolean_set(&itemptr, "flip", flip);
RNA_float_set(&itemptr, "pressure", pressure);
RNA_float_set_array(&itemptr, "location", location);
RNA_float_set_array(&itemptr, "mouse", mouse);
RNA_boolean_set (&itemptr, "pen_flip", pen_flip);
RNA_float_set (&itemptr, "pressure", pressure);
stroke->last_mouse_position[0] = mouse[0];
stroke->last_mouse_position[1] = mouse[1];
@@ -154,10 +852,14 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event)
{
output[0] = event->x;
output[0] = event->x;
output[1] = event->y;
if(stroke->brush->flag & BRUSH_SMOOTH_STROKE && stroke->brush->sculpt_tool != SCULPT_TOOL_GRAB) {
if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
!ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
!(stroke->brush->flag & BRUSH_RESTORE_MESH))
{
float u = stroke->brush->smooth_stroke_factor, v = 1.0 - u;
float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y;
@@ -176,7 +878,9 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *ev
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
static int paint_space_stroke_enabled(Brush *br)
{
return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB);
return (br->flag & BRUSH_SPACE) &&
!(br->flag & BRUSH_ANCHORED) &&
!ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK);
}
/* For brushes with stroke spacing enabled, moves mouse in steps
@@ -187,23 +891,34 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
int cnt = 0;
if(paint_space_stroke_enabled(stroke->brush)) {
float mouse[2] = {stroke->last_mouse_position[0], stroke->last_mouse_position[1]};
float vec[2] = {final_mouse[0] - mouse[0], final_mouse[1] - mouse[1]};
float mouse[2];
float vec[2];
float length, scale;
int steps = 0, i;
/* Normalize the vector between the last stroke dot and the goal */
length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
copy_v2_v2(mouse, stroke->last_mouse_position);
sub_v2_v2v2(vec, final_mouse, mouse);
length = len_v2(vec);
if(length > FLT_EPSILON) {
scale = stroke->brush->spacing / length;
vec[0] *= scale;
vec[1] *= scale;
int steps;
int i;
float pressure = 1;
// XXX duplicate code
if(event->custom == EVT_DATA_TABLET) {
wmTabletData *wmtab= event->customdata;
if(wmtab->Active != EVT_TABLET_NONE)
pressure = stroke->brush->flag & BRUSH_SIZE_PRESSURE ? wmtab->Pressure : 1;
}
scale = (sculpt_get_brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
mul_v2_fl(vec, scale);
steps = (int)(1.0f / scale);
steps = (int)(length / stroke->brush->spacing);
for(i = 0; i < steps; ++i, ++cnt) {
mouse[0] += vec[0];
mouse[1] += vec[1];
add_v2_v2(mouse, vec);
paint_brush_stroke_add_step(C, op, event, mouse);
}
}
@@ -283,14 +998,25 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
//ED_region_tag_redraw(ar);
}
}
else
else {
paint_brush_stroke_add_step(C, op, event, mouse);
}
}
else
;//ED_region_tag_redraw(ar);
}
}
/* we want the stroke to have the first daub at the start location instead of waiting till we have moved the space distance */
if(first &&
stroke->stroke_started &&
paint_space_stroke_enabled(stroke->brush) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
!(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
{
paint_brush_stroke_add_step(C, op, event, mouse);
}
return OPERATOR_RUNNING_MODAL;
}

View File

@@ -216,6 +216,10 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
{CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
{CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
{CURVE_PRESET_MID9, "MID9", 0, "Mid9", ""},
{CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
{CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
{CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
{0, NULL, 0, NULL, NULL}};
ot->name= "Preset";
@@ -225,7 +229,7 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
ot->exec= brush_curve_preset_exec;
ot->poll= brush_curve_preset_poll;
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
ot->flag= OPTYPE_UNDO;
RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
}

View File

@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
* Contributor(s): Jason Wilkins, Tom Musgrove.
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -38,6 +38,8 @@
#include "BLI_ghash.h"
#include "BLI_pbvh.h"
#include "BLI_threads.h"
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
@@ -73,6 +75,7 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "ED_mesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -81,6 +84,7 @@
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
#include "GPU_buffers.h"
@@ -88,13 +92,70 @@
#include <stdlib.h>
#include <string.h>
/* Number of vertices to average in order to determine the flatten distance */
#define FLATTEN_SAMPLE_SIZE 10
#ifdef _OPENMP
#include <omp.h>
#endif
/* ==== FORWARD DEFINITIONS =====
*
*/
static void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void ED_sculpt_force_update(bContext *C)
{
Object *ob= CTX_data_active_object(C);
if(ob && (ob->mode & OB_MODE_SCULPT))
multires_force_update(ob);
}
/* Sculpt mode handles multires differently from regular meshes, but only if
it's the last modifier on the stack and it is not on the first level */
struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
{
ModifierData *md, *nmd;
for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
if(md->type == eModifierType_Multires) {
MultiresModifierData *mmd= (MultiresModifierData*)md;
/* Check if any of the modifiers after multires are active
* if not it can use the multires struct */
for(nmd= md->next; nmd; nmd= nmd->next)
if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
break;
if(!nmd && mmd->sculptlvl > 0)
return mmd;
}
}
return NULL;
}
/* Checks whether full update mode (slower) needs to be used to work with modifiers */
int sculpt_modifiers_active(Scene *scene, Object *ob)
{
ModifierData *md;
MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
/* check if there are any modifiers after what we are sculpting,
for a multires modifier with a deform modifier in front, we
do no need to recalculate the modifier stack. note that this
needs to be in sync with ccgDM_use_grid_pbvh! */
if(mmd)
md= mmd->modifier.next;
else
md= modifiers_getVirtualModifierList(ob);
/* exception for shape keys because we can edit those */
for(; md; md= md->next) {
if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
if(md->type != eModifierType_ShapeKey)
return 1;
}
return 0;
}
/* ===== STRUCTS =====
*
@@ -121,10 +182,13 @@ typedef struct StrokeCache {
/* Variants */
float radius;
float radius_squared;
//float traced_location[3];
float true_location[3];
float location[3];
float flip;
float pen_flip;
float invert;
float pressure;
float mouse[2];
float bstrength;
@@ -141,15 +205,32 @@ typedef struct StrokeCache {
Brush *brush;
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
float rotation; /* Texture rotation (radians) for anchored and rake modes */
float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
int pixel_radius, previous_pixel_radius;
float grab_active_location[8][3];
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
int symmetry; /* Symmetry index between 0 and 7 */
float view_normal[3], view_normal_symmetry[3];
int last_rake[2]; /* Last location of updating rake rotation */
int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
float true_view_normal[3];
float view_normal[3];
float last_area_normal[3];
float last_center[3];
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
float last_rake[2]; /* Last location of updating rake rotation */
int original;
float vertex_rotation;
char saved_active_brush_name[24];
int alt_smooth;
float plane_trim_squared;
float autosmooth_overlap;
} StrokeCache;
/* ===== OPENGL =====
@@ -224,10 +305,12 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
RegionView3D *rv3d, Object *ob)
{
PBVH *pbvh= ob->sculpt->pbvh;
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox");
BoundBox bb;
bglMats mats;
rcti rect;
memset(&bb, 0, sizeof(BoundBox));
view3d_get_transformation(ar, rv3d, ob, &mats);
sculpt_get_redraw_rect(ar, rv3d,ob, &rect);
@@ -246,386 +329,172 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
rect.ymax -= 2;
#endif
view3d_calculate_clipping(bb, planes, &mats, &rect);
view3d_calculate_clipping(&bb, planes, &mats, &rect);
mul_m4_fl(planes, -1.0f);
MEM_freeN(bb);
/* clear redraw flag from nodes */
if(pbvh)
BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
/************************** Undo *************************/
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
char idname[MAX_ID_NAME]; /* name instead of pointer*/
void *node; /* only during push, not valid afterwards! */
float (*co)[3];
short (*no)[3];
int totvert;
/* non-multires */
int maxvert; /* to verify if totvert it still the same */
int *index; /* to restore into right location */
/* multires */
int maxgrid; /* same for grid */
int gridsize; /* same for grid */
int totgrid; /* to restore into right location */
int *grids; /* to restore into right location */
/* layer brush */
float *layer_disp;
/* shape keys */
char *shapeName[32]; /* keep size in sync with keyblock dna */
} SculptUndoNode;
static void update_cb(PBVHNode *node, void *data)
{
BLI_pbvh_node_mark_update(node);
}
/* Checks whether full update mode (slower) needs to be used to work with modifiers */
static int sculpt_modifiers_active(Scene *scene, Object *ob)
{
ModifierData *md;
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
/* check if there are any modifiers after what we are sculpting,
for a multires modifier with a deform modifier in front, we
do no need to recalculate the modifier stack. note that this
needs to be in sync with ccgDM_use_grid_pbvh! */
if(mmd)
md= mmd->modifier.next;
else
md= modifiers_getVirtualModifierList(ob);
/* exception for shape keys because we can edit those */
for(; md; md= md->next) {
if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
if(md->type != eModifierType_ShapeKey)
return 1;
}
return 0;
}
static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
MVert *mvert;
MultiresModifierData *mmd;
int *index;
int i, j, update= 0;
sculpt_update_mesh_elements(scene, ob, 0);
for(unode=lb->first; unode; unode=unode->next) {
if(!(strcmp(unode->idname, ob->id.name)==0))
continue;
if(unode->maxvert) {
char *shapeName= (char*)unode->shapeName;
/* regular mesh restore */
if(ss->totvert != unode->maxvert)
continue;
if (ss->kb && strcmp(ss->kb->name, shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key= ob_get_key(ob);
KeyBlock *kb= key_get_named_keyblock(key, shapeName);
if (kb) {
ob->shapenr= BLI_findindex(&key->block, kb) + 1;
ob->shapeflag|= OB_SHAPE_LOCK;
sculpt_update_mesh_elements(scene, ob, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
} else {
/* key has been removed -- skip this undo node */
continue;
}
}
index= unode->index;
mvert= ss->mvert;
if (ss->kb) {
float (*vertCos)[3];
vertCos= key_to_vertcos(ob, ss->kb);
for(i=0; i<unode->totvert; i++)
swap_v3_v3(vertCos[index[i]], unode->co[i]);
/* propagate new coords to keyblock */
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
MEM_freeN(vertCos);
} else {
for(i=0; i<unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->co[i]);
mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else if(unode->maxgrid && dm->getGridData) {
/* multires restore */
DMGridData **grids, *grid;
float (*co)[3];
int gridsize;
if(dm->getNumGrids(dm) != unode->maxgrid)
continue;
if(dm->getGridSize(dm) != unode->gridsize)
continue;
grids= dm->getGridData(dm);
gridsize= dm->getGridSize(dm);
co = unode->co;
for(j=0; j<unode->totgrid; j++) {
grid= grids[unode->grids[j]];
for(i=0; i<gridsize*gridsize; i++, co++)
swap_v3_v3(grid[i].co, co[0]);
}
}
update= 1;
}
if(update) {
/* we update all nodes still, should be more clever, but also
needs to work correct when exiting/entering sculpt mode and
the nodes get recreated, though in that case it could do all */
BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, NULL);
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
if((mmd=sculpt_multires_active(scene, ob)))
multires_mark_as_modified(ob);
if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
}
}
static void sculpt_undo_free(ListBase *lb)
{
SculptUndoNode *unode;
for(unode=lb->first; unode; unode=unode->next) {
if(unode->co)
MEM_freeN(unode->co);
if(unode->no)
MEM_freeN(unode->no);
if(unode->index)
MEM_freeN(unode->index);
if(unode->grids)
MEM_freeN(unode->grids);
if(unode->layer_disp)
MEM_freeN(unode->layer_disp);
}
}
static SculptUndoNode *sculpt_undo_get_node(SculptSession *ss, PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
if(!lb)
return NULL;
for(unode=lb->first; unode; unode=unode->next)
if(unode->node == node)
return unode;
return NULL;
}
static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
Object *ob= ss->ob;
SculptUndoNode *unode;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
/* list is manipulated by multiple threads, so we lock */
BLI_lock_thread(LOCK_CUSTOM1);
if((unode= sculpt_undo_get_node(ss, node))) {
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
strcpy(unode->idname, ob->id.name);
unode->node= node;
BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
&maxgrid, &gridsize, NULL, NULL);
unode->totvert= totvert;
/* we will use this while sculpting, is mapalloc slow to access then? */
unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
BLI_addtail(lb, unode);
if(maxgrid) {
/* multires */
unode->maxgrid= maxgrid;
unode->totgrid= totgrid;
unode->gridsize= gridsize;
unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
}
else {
/* regular mesh */
unode->maxvert= ss->totvert;
unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
}
BLI_unlock_thread(LOCK_CUSTOM1);
/* copy threaded, hopefully this is the performance critical part */
{
PBVHVertexIter vd;
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
}
BLI_pbvh_vertex_iter_end;
}
if(unode->grids)
memcpy(unode->grids, grids, sizeof(int)*totgrid);
/* store active shape key */
if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
else unode->shapeName[0]= '\0';
return unode;
}
static void sculpt_undo_push_begin(SculptSession *ss, char *name)
{
undo_paint_push_begin(UNDO_PAINT_MESH, name,
sculpt_undo_restore, sculpt_undo_free);
}
static void sculpt_undo_push_end(SculptSession *ss)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
/* we don't need normals in the undo stack */
for(unode=lb->first; unode; unode=unode->next) {
if(unode->no) {
MEM_freeN(unode->no);
unode->no= NULL;
}
if(unode->layer_disp) {
MEM_freeN(unode->layer_disp);
unode->layer_disp= NULL;
}
}
undo_paint_push_end(UNDO_PAINT_MESH);
}
void ED_sculpt_force_update(bContext *C)
{
Object *ob= CTX_data_active_object(C);
if(ob && (ob->mode & OB_MODE_SCULPT))
multires_force_update(ob);
}
/************************ Brush Testing *******************/
typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
} SculptBrushTest;
static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
test->radius_squared= ss->cache->radius*ss->cache->radius;
test->radius_squared= ss->cache->radius_squared;
copy_v3_v3(test->location, ss->cache->location);
}
static int sculpt_brush_test(SculptBrushTest *test, float co[3])
{
float distsq, delta[3];
float distsq = len_squared_v3v3(co, test->location);
sub_v3_v3v3(delta, co, test->location);
distsq = INPR(delta, delta);
if(distsq < test->radius_squared) {
if(distsq <= test->radius_squared) {
test->dist = sqrt(distsq);
return 1;
}
else {
return 0;
}
}
static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
if(distsq <= test->radius_squared) {
test->dist = distsq;
return 1;
}
else {
return 0;
}
}
static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
{
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
{
const static float side = 0.70710678118654752440084436210485; // sqrt(.5);
float local_co[3];
mul_v3_m4v3(local_co, local, co);
local_co[0] = fabs(local_co[0]);
local_co[1] = fabs(local_co[1]);
local_co[2] = fabs(local_co[2]);
if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
return 1;
}
else {
return 0;
}
}
static float frontface(Brush *brush, float sculpt_normal[3], short no[3], float fno[3])
{
if (brush->flag & BRUSH_FRONTFACE) {
float dot;
if (no) {
float tmp[3];
normal_short_to_float_v3(tmp, no);
dot= dot_v3v3(tmp, sculpt_normal);
}
else {
dot= dot_v3v3(fno, sculpt_normal);
}
return dot > 0 ? dot : 0;
}
else {
return 1;
}
}
#if 0
static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
{
if (sculpt_brush_test_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
cross_v3_v3v3(t3, an, t1);
dist = len_v3(t3)/len_v3(t2);
test->dist = dist;
return 1;
}
return 0;
}
#endif
/* ===== Sculpting =====
*
*/
/* Return modified brush strength. Includes the direction of the brush, positive
values pull vertices, negative values push. Uses tablet pressure and a
special multiplier found experimentally to scale the strength factor. */
static float brush_strength(Sculpt *sd, StrokeCache *cache)
static float overlapped_curve(Brush* br, float x)
{
Brush *brush = paint_brush(&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
float alpha = brush->alpha * brush->alpha;
int i;
const int n = 100 / br->spacing;
const float h = br->spacing / 50.0f;
const float x0 = x-1;
float dir= brush->flag & BRUSH_DIR_IN ? -1 : 1;
float pressure= 1;
float flip= cache->flip ? -1:1;
float sum;
if(brush->flag & BRUSH_ALPHA_PRESSURE)
pressure *= cache->pressure;
switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_INFLATE:
case SCULPT_TOOL_CLAY:
case SCULPT_TOOL_FLATTEN:
case SCULPT_TOOL_LAYER:
return alpha * dir * pressure * flip; /*XXX: not sure why? was multiplied by G.vd->grid */;
case SCULPT_TOOL_SMOOTH:
return alpha * 4 * pressure;
case SCULPT_TOOL_PINCH:
return alpha / 2 * dir * pressure * flip;
case SCULPT_TOOL_GRAB:
return 1;
default:
return 0;
sum = 0;
for (i= 0; i < n; i++) {
float xx;
xx = fabs(x0 + i*h);
if (xx < 1.0f)
sum += brush_curve_strength(br, xx, 1);
}
return sum;
}
static float integrate_overlap(Brush* br)
{
int i;
int m= 10;
float g = 1.0f/m;
float overlap;
float max;
overlap= 0;
max= 0;
for(i= 0; i < m; i++) {
overlap = overlapped_curve(br, i*g);
if (overlap > max)
max = overlap;
}
return max;
}
/* Uses symm to selectively flip any axis of a coordinate. */
@@ -645,6 +514,166 @@ static void flip_coord(float out[3], float in[3], const char symm)
out[2]= in[2];
}
float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
float mirror[3];
float distsq;
float mat[4][4];
//flip_coord(mirror, cache->traced_location, symm);
flip_coord(mirror, cache->true_location, symm);
unit_m4(mat);
rotate_m4(mat, axis, angle);
mul_m4_v3(mat, mirror);
//distsq = len_squared_v3v3(mirror, cache->traced_location);
distsq = len_squared_v3v3(mirror, cache->true_location);
if (distsq <= 4*(cache->radius_squared))
return (2*(cache->radius) - sqrt(distsq)) / (2*(cache->radius));
else
return 0;
}
static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, const char symm, const char axis)
{
int i;
float overlap;
overlap = 0;
for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
overlap += calc_overlap(cache, symm, axis, angle);
}
return overlap;
}
static float calc_symmetry_feather(Sculpt *sd, StrokeCache* cache)
{
if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
float overlap;
int symm = cache->symmetry;
int i;
overlap = 0;
for (i = 0; i <= symm; i++) {
if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
overlap += calc_overlap(cache, i, 0, 0);
overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
}
}
return 1/overlap;
}
else {
return 1;
}
}
/* Return modified brush strength. Includes the direction of the brush, positive
values pull vertices, negative values push. Uses tablet pressure and a
special multiplier found experimentally to scale the strength factor. */
static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, float overlap)
{
Brush *brush = paint_brush(&sd->paint);
/* Primary strength input; square it to make lower values more sensitive */
float alpha = sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush);
float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
float pressure = brush->flag & BRUSH_ALPHA_PRESSURE ? cache->pressure : 1;
float pen_flip = cache->pen_flip ? -1 : 1;
float invert = cache->invert ? -1 : 1;
float flip = dir * invert * pen_flip;
switch(brush->sculpt_tool){
case SCULPT_TOOL_CLAY:
case SCULPT_TOOL_CLAY_TUBES:
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_CREASE:
case SCULPT_TOOL_BLOB:
return alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_INFLATE:
if (flip > 0) {
return 0.250f * alpha * flip * pressure * overlap * feather;
}
else {
return 0.125f * alpha * flip * pressure * overlap * feather;
}
case SCULPT_TOOL_FILL:
case SCULPT_TOOL_SCRAPE:
case SCULPT_TOOL_FLATTEN:
if (flip > 0) {
overlap = (1+overlap) / 2;
return alpha * flip * pressure * overlap * feather;
}
else {
/* reduce strength for DEEPEN, PEAKS, and CONTRAST */
return 0.5f * alpha * flip * pressure * overlap * feather;
}
case SCULPT_TOOL_SMOOTH:
return alpha * pressure * feather;
case SCULPT_TOOL_PINCH:
if (flip > 0) {
return alpha * flip * pressure * overlap * feather;
}
else {
return 0.25f * alpha * flip * pressure * overlap * feather;
}
case SCULPT_TOOL_NUDGE:
overlap = (1+overlap) / 2;
return alpha * pressure * overlap * feather;
case SCULPT_TOOL_THUMB:
return alpha*pressure*feather;
case SCULPT_TOOL_SNAKE_HOOK:
return feather;
case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_ROTATE:
return feather;
default:
return 0;
}
}
float get_tex_pixel(Brush* br, float u, float v)
{
TexResult texres;
float co[3];
int hasrgb;
co[0] = u;
co[1] = v;
co[2] = 0;
memset(&texres, 0, sizeof(TexResult));
hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 1, &texres);
if (hasrgb & TEX_RGB)
texres.tin = (0.35*texres.tr + 0.45*texres.tg + 0.2*texres.tb)*texres.ta;
return texres.tin;
}
#if 0
/* Get a pixel from the texcache at (px, py) */
static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
{
@@ -655,7 +684,7 @@ static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
{
int x, y, x2, y2;
unsigned x, y, x2, y2;
const int tc_max = ss->texcache_side - 1;
float urat, vrat, uopp;
@@ -682,76 +711,97 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
}
#endif
/* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
{
MTex *tex = &br->mtex;
MTex *mtex = &br->mtex;
float avg= 1;
if(!tex) {
if(!mtex->tex) {
avg= 1;
}
else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
else if(mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
float jnk;
/* Get strength by feeding the vertex
location directly into a texture */
externtex(tex, point, &avg,
externtex(mtex, point, &avg,
&jnk, &jnk, &jnk, &jnk);
}
else if(ss->texcache) {
const float bsize= ss->cache->pixel_radius * 2;
const float rot= tex->rot + ss->cache->rotation;
int px, py;
float flip[3], point_2d[2];
float rotation = -mtex->rot;
float x, y, point_2d[3];
float diameter;
/* If the active area is being applied for symmetry, flip it
across the symmetry axis in order to project it. This insures
that the brush texture will be oriented correctly. */
copy_v3_v3(flip, point);
flip_coord(flip, flip, ss->cache->symmetry);
projectf(ss->cache->mats, flip, point_2d);
/* if the active area is being applied for symmetry, flip it
across the symmetry axis and rotate it back to the orignal
position in order to project it. This insures that the
brush texture will be oriented correctly. */
/* For Tile and Drag modes, get the 2D screen coordinates of the
and scale them up or down to the texture size. */
if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
const int sx= (const int)tex->size[0];
const int sy= (const int)tex->size[1];
float fx= point_2d[0];
float fy= point_2d[1];
float angle= atan2(fy, fx) - rot;
float flen= sqrtf(fx*fx + fy*fy);
if(rot<0.001 && rot>-0.001) {
px= point_2d[0];
py= point_2d[1];
} else {
px= flen * cos(angle) + 2000;
py= flen * sin(angle) + 2000;
}
if(sx != 1)
px %= sx-1;
if(sy != 1)
py %= sy-1;
avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
flip_coord(point_2d, point, ss->cache->mirror_symmetry_pass);
if (ss->cache->radial_symmetry_pass)
mul_m4_v3(ss->cache->symm_rot_mat_inv, point_2d);
projectf(ss->cache->mats, point_2d, point_2d);
/* if fixed mode, keep coordinates relative to mouse */
if(mtex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
rotation += ss->cache->special_rotation;
point_2d[0] -= ss->cache->tex_mouse[0];
point_2d[1] -= ss->cache->tex_mouse[1];
diameter = ss->cache->pixel_radius; // use pressure adjusted size for fixed mode
x = point_2d[0];
y = point_2d[1];
}
else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
float fx= (point_2d[0] - ss->cache->tex_mouse[0]) / bsize;
float fy= (point_2d[1] - ss->cache->tex_mouse[1]) / bsize;
float angle= atan2(fy, fx) - rot;
float flen= sqrtf(fx*fx + fy*fy);
fx = flen * cos(angle) + 0.5;
fy = flen * sin(angle) + 0.5;
avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
else /* else (mtex->brush_map_mode == MTEX_MAP_MODE_TILED),
leave the coordinates relative to the screen */
{
diameter = sculpt_get_brush_size(br); // use unadjusted size for tiled mode
x = point_2d[0] - ss->cache->vc->ar->winrct.xmin;
y = point_2d[1] - ss->cache->vc->ar->winrct.ymin;
}
x /= ss->cache->vc->ar->winx;
y /= ss->cache->vc->ar->winy;
if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
x -= 0.5f;
y -= 0.5f;
}
x *= ss->cache->vc->ar->winx / diameter;
y *= ss->cache->vc->ar->winy / diameter;
/* it is probably worth optimizing for those cases where
the texture is not rotated by skipping the calls to
atan2, sqrtf, sin, and cos. */
if (rotation > 0.001 || rotation < -0.001) {
const float angle = atan2(y, x) + rotation;
const float flen = sqrtf(x*x + y*y);
x = flen * cos(angle);
y = flen * sin(angle);
}
x *= br->mtex.size[0];
y *= br->mtex.size[1];
x += br->mtex.ofs[0];
y += br->mtex.ofs[1];
avg = get_tex_pixel(br, x, y);
}
avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
avg += br->texture_sample_bias;
avg *= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
return avg;
}
@@ -787,7 +837,7 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
sub_v3_v3v3(t, center, nearest);
return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
return dot_v3v3(t, t) < data->radius_squared;
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
@@ -803,7 +853,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va
co[i]= 0.0f;
else
co[i]= val[i];
}
}
}
static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
@@ -815,52 +865,48 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa
}
}
/* For draw/layer/flatten; finds average normal for all active vertices */
static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode)
static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
{
PBVH *bvh= ss->pbvh;
StrokeCache *cache = ss->cache;
const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
float out[3] = {0.0f, 0.0f, 0.0f};
float out_flip[3] = {0.0f, 0.0f, 0.0f};
float out_dir[3];
int n;
copy_v3_v3(out_dir, cache->view_normal_symmetry);
float out_flip[3] = {0.0f, 0.0f, 0.0f};
/* threaded loop over nodes */
//#pragma omp parallel for private(n) schedule(static)
zero_v3(an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
SculptUndoNode *unode;
float fno[3];
float nout[3] = {0.0f, 0.0f, 0.0f};
float nout_flip[3] = {0.0f, 0.0f, 0.0f};
// XXX push instead of get for thread safety in draw
// brush .. lame, but also not harmful really
unode= sculpt_undo_push_node(ss, nodes[n]);
float private_an[3] = {0.0f, 0.0f, 0.0f};
float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
unode = sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
if(ss->cache->original) {
BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, unode->co[vd.i])) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
float fno[3];
normal_short_to_float_v3(fno, unode->no[vd.i]);
add_norm_if(out_dir, nout, nout_flip, fno);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
}
BLI_pbvh_vertex_iter_end;
}
else {
BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, vd.co)) {
if(vd.no) {
float fno[3];
normal_short_to_float_v3(fno, vd.no);
add_norm_if(out_dir, nout, nout_flip, fno);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
else {
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
}
else
add_norm_if(out_dir, nout, nout_flip, vd.fno);
}
}
BLI_pbvh_vertex_iter_end;
@@ -868,72 +914,70 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3]
//#pragma omp critical
{
/* we sum per node and add together later for threads */
add_v3_v3(out, nout);
add_v3_v3(out_flip, nout_flip);
add_v3_v3(an, private_an);
add_v3_v3(out_flip, private_out_flip);
}
}
if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
copy_v3_v3(out, out_flip);
}
normalize_v3(out);
if (is_zero_v3(an))
copy_v3_v3(an, out_flip);
out[0] = out_dir[0] * view + out[0] * (10-view);
out[1] = out_dir[1] * view + out[1] * (10-view);
out[2] = out_dir[2] * view + out[2] * (10-view);
normalize_v3(out);
copy_v3_v3(area_normal, out);
normalize_v3(an);
}
static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
/* This initializes the faces to be moved for this sculpt for draw/layer/flatten; then it
finds average normal for all active vertices - note that this is called once for each mirroring direction */
static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
int n;
/* area normal */
calc_area_normal(sd, ss, area_normal, nodes, totnode);
if (ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0 &&
(ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
viewvector(ss->cache->vc->rv3d, ss->cache->vc->rv3d->twmat[3], an);
break;
/* offset with as much as possible factored in already */
offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength;
offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength;
offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength;
case SCULPT_DISP_DIR_X:
an[1] = 0.0;
an[2] = 0.0;
an[0] = 1.0;
break;
/* threaded loop over nodes */
//#pragma omp parallel for private(n) schedule(static)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
case SCULPT_DISP_DIR_Y:
an[0] = 0.0;
an[2] = 0.0;
an[1] = 1.0;
break;
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
float fade = tex_strength(ss, brush, vd.co, test.dist);
float val[3]= {vd.co[0] + offset[0]*fade,
vd.co[1] + offset[1]*fade,
vd.co[2] + offset[2]*fade};
case SCULPT_DISP_DIR_Z:
an[0] = 0.0;
an[1] = 0.0;
an[2] = 1.0;
break;
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
case SCULPT_DISP_DIR_AREA:
calc_area_normal(sd, ss, an, nodes, totnode);
default:
break;
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
copy_v3_v3(ss->cache->last_area_normal, an);
}
else {
copy_v3_v3(an, ss->cache->last_area_normal);
flip_coord(an, an, ss->cache->mirror_symmetry_pass);
mul_m4_v3(ss->cache->symm_rot_mat, an);
}
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
a smoothed location for vert. Skips corner vertices (used by only one
polygon.) */
static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
static void neighbor_average(SculptSession *ss, float avg[3], const unsigned vert)
{
int i, skip= -1, total=0;
IndexNode *node= ss->fmap[vert].first;
@@ -974,52 +1018,58 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
copy_v3_v3(avg, ss->mvert[vert].co);
}
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
PBVHVertexIter vd;
SculptBrushTest test;
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float avg[3], val[3];
CLAMP(fade, 0.0f, 1.0f);
neighbor_average(ss, avg, vd.vert_indices[vd.i]);
val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade;
val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade;
val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade;
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
sub_v3_v3v3(val, avg, vd.co);
mul_v3_fl(val, fade);
add_v3_v3(val, vd.co);
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
{
Brush *brush = paint_brush(&sd->paint);
SculptBrushTest test;
DMGridData **griddata, *data;
DMGridAdjacency *gridadj, *adj;
float bstrength= ss->cache->bstrength;
float co[3], (*tmpgrid)[3];
float (*tmpgrid)[3], (*tmprow)[3];
int v1, v2, v3, v4;
int *grid_indices, totgrid, gridsize, i, x, y;
sculpt_brush_test_init(ss, &test);
CLAMP(bstrength, 0.0f, 1.0f);
BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
NULL, &gridsize, &griddata, &gridadj);
//#pragma omp critical
tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
{
tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
tmprow= MEM_mallocN(sizeof(float)*3*gridsize, "tmprow");
}
for(i = 0; i < totgrid; ++i) {
data = griddata[grid_indices[i]];
@@ -1027,75 +1077,106 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
memset(tmpgrid, 0, sizeof(float)*3*gridsize*gridsize);
/* average grid values */
for(y = 0; y < gridsize-1; ++y) {
for(x = 0; x < gridsize-1; ++x) {
for (y= 0; y < gridsize-1; y++) {
float tmp[3];
v1 = y*gridsize;
add_v3_v3v3(tmprow[0], data[v1].co, data[v1+gridsize].co);
for (x= 0; x < gridsize-1; x++) {
v1 = x + y*gridsize;
v2 = (x + 1) + y*gridsize;
v3 = (x + 1) + (y + 1)*gridsize;
v4 = x + (y + 1)*gridsize;
v2 = v1 + 1;
v3 = v1 + gridsize;
v4 = v3 + 1;
cent_quad_v3(co, data[v1].co, data[v2].co, data[v3].co, data[v4].co);
mul_v3_fl(co, 0.25f);
add_v3_v3v3(tmprow[x+1], data[v2].co, data[v4].co);
add_v3_v3v3(tmp, tmprow[x+1], tmprow[x]);
add_v3_v3(tmpgrid[v1], co);
add_v3_v3(tmpgrid[v2], co);
add_v3_v3(tmpgrid[v3], co);
add_v3_v3(tmpgrid[v4], co);
add_v3_v3(tmpgrid[v1], tmp);
add_v3_v3(tmpgrid[v2], tmp);
add_v3_v3(tmpgrid[v3], tmp);
add_v3_v3(tmpgrid[v4], tmp);
}
}
/* blend with existing coordinates */
for(y = 0; y < gridsize; ++y) {
for(x = 0; x < gridsize; ++x) {
if(x == 0 && adj->index[0] == -1) continue;
if(x == gridsize - 1 && adj->index[2] == -1) continue;
if(y == 0 && adj->index[3] == -1) continue;
if(y == gridsize - 1 && adj->index[1] == -1) continue;
float *co;
float *fno;
int index;
copy_v3_v3(co, data[x + y*gridsize].co);
if(x == 0 && adj->index[0] == -1)
continue;
if(x == gridsize - 1 && adj->index[2] == -1)
continue;
if(y == 0 && adj->index[3] == -1)
continue;
if(y == gridsize - 1 && adj->index[1] == -1)
continue;
index = x + y*gridsize;
co= data[index].co;
fno= data[index].no;
if(sculpt_brush_test(&test, co)) {
float fade = tex_strength(ss, brush, co, test.dist)*bstrength;
float avg[3], val[3];
const float fade = bstrength*tex_strength(ss, brush, co, test.dist)*frontface(brush, ss->cache->view_normal, NULL, fno);
float *avg, val[3];
float n;
avg = tmpgrid[x + y*gridsize];
n = 1/16.0f;
copy_v3_v3(avg, tmpgrid[x + y*gridsize]);
if(x == 0 || x == gridsize - 1)
mul_v3_fl(avg, 2.0f);
n *= 2;
if(y == 0 || y == gridsize - 1)
mul_v3_fl(avg, 2.0f);
n *= 2;
CLAMP(fade, 0.0f, 1.0f);
mul_v3_fl(avg, n);
val[0] = co[0]+(avg[0]-co[0])*fade;
val[1] = co[1]+(avg[1]-co[1])*fade;
val[2] = co[2]+(avg[2]-co[2])*fade;
sculpt_clip(sd, ss, data[x + y*gridsize].co, val);
sub_v3_v3v3(val, avg, co);
mul_v3_fl(val, fade);
add_v3_v3(val, co);
sculpt_clip(sd, ss, co, val);
}
}
}
}
//#pragma omp critical
MEM_freeN(tmpgrid);
{
MEM_freeN(tmpgrid);
MEM_freeN(tmprow);
}
}
static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float bstrength)
{
int iteration, n;
const int max_iterations = 4;
const float fract = 1.0f/max_iterations;
int iteration, n, count;
float last;
for(iteration = 0; iteration < 2; ++iteration) {
//#pragma omp parallel for private(n) schedule(static)
CLAMP(bstrength, 0, 1);
count = (int)(bstrength*max_iterations);
last = max_iterations*(bstrength - count*fract);
for(iteration = 1; iteration <= count; ++iteration) {
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
sculpt_undo_push_node(ss, nodes[n]);
if(ss->multires)
do_multires_smooth_brush(sd, ss, nodes[n]);
if(ss->multires) {
do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
else if(ss->fmap)
do_mesh_smooth_brush(sd, ss, nodes[n]);
BLI_pbvh_node_mark_update(nodes[n]);
do_mesh_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
if(ss->multires)
@@ -1103,69 +1184,378 @@ static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
smooth(sd, ss, nodes, totnode, ss->cache->bstrength);
}
static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
int n;
calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, area_normal, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test(&test, vd.co)) {
//if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, area_normal)) {
/* offset vertex */
float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], offset, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
float flippedbstrength, crease_correction;
int n;
calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, area_normal, ss->cache->radius);
mul_v3_v3(offset, ss->cache->scale);
mul_v3_fl(offset, bstrength);
/* we divide out the squared alpha and multiply by the squared crease to give us the pinch strength */
if(sculpt_get_brush_alpha(brush) > 0.0f)
crease_correction = brush->crease_pinch_factor*brush->crease_pinch_factor/(sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush));
else
crease_correction = brush->crease_pinch_factor*brush->crease_pinch_factor;
/* we always want crease to pinch or blob to relax even when draw is negative */
flippedbstrength = (bstrength < 0) ? -crease_correction*bstrength : crease_correction*bstrength;
if(brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
/* threaded loop over nodes */
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
const float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
float val1[3];
float val2[3];
/* first we pinch */
sub_v3_v3v3(val1, test.location, vd.co);
//mul_v3_v3(val1, ss->cache->scale);
mul_v3_fl(val1, fade*flippedbstrength);
/* then we draw */
mul_v3_v3fl(val2, offset, fade);
add_v3_v3v3(proxy[vd.i], val1, val2);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
int n;
//#pragma omp parallel for private(n) schedule(static)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
sculpt_undo_push_node(ss, nodes[n]);
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
float val[3]= {vd.co[0]+(test.location[0]-vd.co[0])*fade,
vd.co[1]+(test.location[1]-vd.co[1])*fade,
vd.co[2]+(test.location[2]-vd.co[2])*fade};
float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float val[3];
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
sub_v3_v3v3(val, test.location, vd.co);
mul_v3_v3fl(proxy[vd.i], val, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
}
}
static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
Brush *brush= paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float grab_delta[3];
float grab_delta[3], an[3];
int n;
float len;
if (brush->normal_weight > 0)
calc_sculpt_normal(sd, ss, an, nodes, totnode);
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
//#pragma omp parallel for private(n) schedule(static)
len = len_v3(grab_delta);
if (brush->normal_weight > 0) {
mul_v3_fl(an, len*brush->normal_weight);
mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
add_v3_v3(grab_delta, an);
}
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptUndoNode* unode;
SculptBrushTest test;
float (*origco)[3];
origco= sculpt_undo_push_node(ss, nodes[n])->co;
short (*origno)[3];
float (*proxy)[3];
unode= sculpt_undo_push_node(ss, nodes[n]);
origco= unode->co;
origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
float fade = tex_strength(ss, brush, origco[vd.i], test.dist)*bstrength;
float add[3]= {vd.co[0]+fade*grab_delta[0],
vd.co[1]+fade*grab_delta[1],
vd.co[2]+fade*grab_delta[2]};
const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
sculpt_clip(sd, ss, vd.co, add);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
BLI_pbvh_node_mark_update(nodes[n]);
static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3];
int n;
float an[3];
float tmp[3], cono[3];
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
calc_sculpt_normal(sd, ss, an, nodes, totnode);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], cono, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3], an[3];
int n;
float len;
if (brush->normal_weight > 0)
calc_sculpt_normal(sd, ss, an, nodes, totnode);
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
len = len_v3(grab_delta);
if (bstrength < 0)
negate_v3(grab_delta);
if (brush->normal_weight > 0) {
mul_v3_fl(an, len*brush->normal_weight);
mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
add_v3_v3(grab_delta, an);
}
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float grab_delta[3];
int n;
float an[3];
float tmp[3], cono[3];
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
calc_sculpt_normal(sd, ss, an, nodes, totnode);
cross_v3_v3v3(tmp, an, grab_delta);
cross_v3_v3v3(cono, tmp, an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptUndoNode* unode;
SculptBrushTest test;
float (*origco)[3];
short (*origno)[3];
float (*proxy)[3];
unode= sculpt_undo_push_node(ss, nodes[n]);
origco= unode->co;
origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
mul_v3_v3fl(proxy[vd.i], cono, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush= paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float an[3];
int n;
float m[3][3];
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
calc_sculpt_normal(sd, ss, an, nodes, totnode);
axis_angle_to_mat3(m, an, angle);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptUndoNode* unode;
SculptBrushTest test;
float (*origco)[3];
short (*origno)[3];
float (*proxy)[3];
unode= sculpt_undo_push_node(ss, nodes[n]);
origco= unode->co;
origno= unode->no;
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
mul_v3_m3v3(proxy[vd.i], m, origco[vd.i]);
sub_v3_v3(proxy[vd.i], origco[vd.i]);
mul_v3_fl(proxy[vd.i], fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
}
@@ -1177,63 +1567,66 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
float lim= ss->cache->radius / 4;
int n;
if(ss->cache->flip)
if(bstrength < 0)
lim = -lim;
calc_area_normal(sd, ss, area_normal, nodes, totnode);
calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
offset[0]= ss->cache->scale[0]*area_normal[0];
offset[1]= ss->cache->scale[1]*area_normal[1];
offset[2]= ss->cache->scale[2]*area_normal[2];
mul_v3_v3v3(offset, ss->cache->scale, area_normal);
//#pragma omp parallel for private(n) schedule(static)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
SculptUndoNode *unode;
float (*origco)[3], *layer_disp;
//float (*proxy)[3]; // XXX layer brush needs conversion to proxy but its more complicated
//proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
unode= sculpt_undo_push_node(ss, nodes[n]);
origco=unode->co;
if(!unode->layer_disp)
unode->layer_disp= MEM_callocN(sizeof(float)*unode->totvert, "layer disp");
{
#pragma omp critical
unode->layer_disp= MEM_callocN(sizeof(float)*unode->totvert, "layer disp");
}
layer_disp= unode->layer_disp;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
const float fade = bstrength*ss->cache->radius*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
float *disp= &layer_disp[vd.i];
float val[3];
*disp+= fade;
/* Don't let the displacement go past the limit */
if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
*disp = lim;
mul_v3_v3fl(val, offset, *disp);
if(ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
int index= vd.vert_indices[vd.i];
/* persistent base */
val[0] = ss->layer_co[index][0] + (*disp)*offset[0];
val[1] = ss->layer_co[index][1] + (*disp)*offset[1];
val[2] = ss->layer_co[index][2] + (*disp)*offset[2];
add_v3_v3(val, ss->layer_co[index]);
}
else {
val[0] = origco[vd.i][0] + (*disp)*offset[0];
val[1] = origco[vd.i][1] + (*disp)*offset[1];
val[2] = origco[vd.i][2] + (*disp)*offset[2];
add_v3_v3(val, origco[vd.i]);
}
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
}
}
@@ -1243,177 +1636,634 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
float bstrength= ss->cache->bstrength;
int n;
//#pragma omp parallel for private(n) schedule(static)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
sculpt_undo_push_node(ss, nodes[n]);
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
float add[3];
const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float val[3];
if(vd.fno) copy_v3_v3(add, vd.fno);
else normal_short_to_float_v3(add, vd.no);
if(vd.fno) copy_v3_v3(val, vd.fno);
else normal_short_to_float_v3(val, vd.no);
mul_v3_fl(add, fade * ss->cache->radius);
add[0]*= ss->cache->scale[0];
add[1]*= ss->cache->scale[1];
add[2]*= ss->cache->scale[2];
add_v3_v3(add, vd.co);
sculpt_clip(sd, ss, vd.co, add);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
mul_v3_fl(val, fade * ss->cache->radius);
mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
}
}
static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3])
static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float fc[3])
{
float outer_dist[FLATTEN_SAMPLE_SIZE];
float outer_co[FLATTEN_SAMPLE_SIZE][3];
int i, n;
for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
zero_v3(outer_co[i]);
outer_dist[i]= -1.0f;
}
//#pragma omp parallel for private(n) schedule(static)
int n;
float count = 0;
zero_v3(fc);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
int j;
sculpt_undo_push_node(ss, nodes[n]);
SculptUndoNode *unode;
float private_fc[3] = {0.0f, 0.0f, 0.0f};
int private_count = 0;
unode = sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
for(j = 0; j < FLATTEN_SAMPLE_SIZE; ++j) {
if(test.dist > outer_dist[j]) {
copy_v3_v3(outer_co[j], vd.co);
outer_dist[j] = test.dist;
break;
}
if(ss->cache->original) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
BLI_pbvh_vertex_iter_end;
}
else {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, vd.co)) {
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
BLI_pbvh_vertex_iter_end;
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
#pragma omp critical
{
add_v3_v3(fc, private_fc);
count += private_count;
}
}
mul_v3_fl(fc, 1.0f / count);
}
/* this calculates flatten center and area normal together,
amortizing the memory bandwidth and loop overhead to calculate both at the same time */
static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
{
int n;
// an
float out_flip[3] = {0.0f, 0.0f, 0.0f};
// fc
float count = 0;
// an
zero_v3(an);
// fc
zero_v3(fc);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
SculptUndoNode *unode;
float private_an[3] = {0.0f, 0.0f, 0.0f};
float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
float private_fc[3] = {0.0f, 0.0f, 0.0f};
int private_count = 0;
unode = sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
if(ss->cache->original) {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
// an
float fno[3];
normal_short_to_float_v3(fno, unode->no[vd.i]);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
// fc
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
BLI_pbvh_vertex_iter_end;
}
else {
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test_fast(&test, vd.co)) {
// an
if(vd.no) {
float fno[3];
normal_short_to_float_v3(fno, vd.no);
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
else {
add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
}
// fc
add_v3_v3(private_fc, vd.co);
private_count++;
}
}
BLI_pbvh_vertex_iter_end;
}
#pragma omp critical
{
// an
add_v3_v3(an, private_an);
add_v3_v3(out_flip, private_out_flip);
// fc
add_v3_v3(fc, private_fc);
count += private_count;
}
}
// an
if (is_zero_v3(an))
copy_v3_v3(an, out_flip);
normalize_v3(an);
// fc
mul_v3_fl(fc, 1.0f / count);
}
static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
{
Brush *brush = paint_brush(&sd->paint);
if (ss->cache->mirror_symmetry_pass == 0 &&
ss->cache->radial_symmetry_pass == 0 &&
(ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
{
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
viewvector(ss->cache->vc->rv3d, ss->cache->vc->rv3d->twmat[3], an);
break;
case SCULPT_DISP_DIR_X:
an[1] = 0.0;
an[2] = 0.0;
an[0] = 1.0;
break;
case SCULPT_DISP_DIR_Y:
an[0] = 0.0;
an[2] = 0.0;
an[1] = 1.0;
break;
case SCULPT_DISP_DIR_Z:
an[0] = 0.0;
an[1] = 0.0;
an[2] = 1.0;
break;
case SCULPT_DISP_DIR_AREA:
calc_area_normal_and_flatten_center(sd, ss, nodes, totnode, an, fc);
default:
break;
}
// fc
/* flatten center has not been calculated yet if we are not using the area normal */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
calc_flatten_center(sd, ss, nodes, totnode, fc);
// an
copy_v3_v3(ss->cache->last_area_normal, an);
// fc
copy_v3_v3(ss->cache->last_center, fc);
}
else {
// an
copy_v3_v3(an, ss->cache->last_area_normal);
// fc
copy_v3_v3(fc, ss->cache->last_center);
// an
flip_coord(an, an, ss->cache->mirror_symmetry_pass);
// fc
flip_coord(fc, fc, ss->cache->mirror_symmetry_pass);
// an
mul_m4_v3(ss->cache->symm_rot_mat, an);
// fc
mul_m4_v3(ss->cache->symm_rot_mat, fc);
}
co[0] = co[1] = co[2] = 0.0f;
for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
if(outer_dist[i] >= 0.0f)
add_v3_v3(co, outer_co[i]);
mul_v3_fl(co, 1.0f / FLATTEN_SAMPLE_SIZE);
}
/* Projects a point onto a plane along the plane's normal */
static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
{
float p1[3], sub1[3], sub2[3];
/* Find the intersection between squash-plane and vertex (along the area normal) */
sub_v3_v3v3(p1, co, plane_normal);
sub_v3_v3v3(sub1, plane_center, p1);
sub_v3_v3v3(sub2, co, p1);
sub_v3_v3v3(intr, co, p1);
mul_v3_fl(intr, dot_v3v3(plane_normal, sub1) / dot_v3v3(plane_normal, sub2));
add_v3_v3(intr, p1);
sub_v3_v3v3(intr, co, plane_center);
mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
sub_v3_v3v3(intr, co, intr);
}
static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip)
static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
{
float delta[3];
float d;
sub_v3_v3v3(delta, co, plane_center);
d = dot_v3v3(plane_normal, delta);
if(flip)
d = -d;
return d <= 0.0f;
return !(brush->flag & BRUSH_PLANE_TRIM) || (dot_v3v3(val, val) <= cache->radius_squared*cache->plane_trim_squared);
}
static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay)
static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
{
/* area_normal and cntr define the plane towards which vertices are squashed */
Brush *brush = paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
float area_normal[3];
float cntr[3], cntr2[3] = {0}, bstr = 0;
int n, flip = 0;
float delta[3];
float d;
calc_area_normal(sd, ss, area_normal, nodes, totnode);
calc_flatten_center(sd, ss, nodes, totnode, cntr);
sub_v3_v3v3(delta, co, plane_center);
d = dot_v3v3(plane_normal, delta);
if(clay) {
bstr= brush_strength(sd, ss->cache);
/* Limit clay application to here */
cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0];
cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1];
cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
flip = bstr < 0;
if (flip) d = -d;
return d <= 0.0f;
}
static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
{
float delta[3];
sub_v3_v3v3(delta, co, plane_center);
return dot_v3v3(plane_normal, delta) <= 0.0f;
}
static float get_offset(Sculpt *sd, SculptSession *ss)
{
Brush* brush = paint_brush(&sd->paint);
float rv = brush->plane_offset;
if (brush->flag & BRUSH_OFFSET_PRESSURE) {
rv *= ss->cache->pressure;
}
//#pragma omp parallel for private(n) schedule(static)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
return rv;
}
static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float an[3];
float fc[3];
float offset = get_offset(sd, ss);
float displace;
int n;
float temp[3];
calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
displace = radius*offset;
mul_v3_v3v3(temp, an, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
sculpt_undo_push_node(ss, nodes[n]);
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
float intr[3], val[3];
if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) {
const float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
if (sculpt_brush_test_sq(&test, vd.co)) {
float intr[3];
float val[3];
/* Find the intersection between squash-plane and vertex (along the area normal) */
point_plane_project(intr, vd.co, area_normal, cntr);
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
sub_v3_v3v3(val, intr, vd.co);
if(clay) {
if(bstr > FLT_EPSILON)
mul_v3_fl(val, fade / bstr);
else
mul_v3_fl(val, fade);
/* Clay displacement */
val[0]+=area_normal[0] * ss->cache->scale[0]*fade;
val[1]+=area_normal[1] * ss->cache->scale[1]*fade;
val[2]+=area_normal[2] * ss->cache->scale[2]*fade;
}
else
mul_v3_fl(val, fabs(fade));
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
add_v3_v3(val, vd.co);
mul_v3_v3fl(proxy[vd.i], val, fade);
sculpt_clip(sd, ss, vd.co, val);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
}
}
static void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float radius = ss->cache->radius;
float offset = get_offset(sd, ss);
float displace;
float an[3]; // area normal
float fc[3]; // flatten center
int n;
float temp[3];
//float p[3];
int flip;
calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
flip = bstrength < 0;
if (flip) {
bstrength = -bstrength;
radius = -radius;
}
displace = radius * (0.25f+offset);
mul_v3_v3v3(temp, an, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
//add_v3_v3v3(p, ss->cache->location, an);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test_sq(&test, vd.co)) {
if (plane_point_side_flip(vd.co, an, fc, flip)) {
//if (sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, p)) {
float intr[3];
float val[3];
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
float radius = ss->cache->radius;
float offset = get_offset(sd, ss);
float displace;
float sn[3]; // sculpt normal
float an[3]; // area normal
float fc[3]; // flatten center
int n;
float temp[3];
float mat[4][4];
float scale[4][4];
float tmat[4][4];
int flip;
calc_sculpt_plane(sd, ss, nodes, totnode, sn, fc);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
calc_area_normal(sd, ss, an, nodes, totnode);
else
copy_v3_v3(an, sn);
if (ss->cache->first_time)
return; // delay the first daub because grab delta is not setup
flip = bstrength < 0;
if (flip) {
bstrength = -bstrength;
radius = -radius;
}
displace = radius * (0.25f+offset);
mul_v3_v3v3(temp, sn, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry); mat[0][3] = 0;
cross_v3_v3v3(mat[1], an, mat[0]); mat[1][3] = 0;
copy_v3_v3(mat[2], an); mat[2][3] = 0;
copy_v3_v3(mat[3], ss->cache->location); mat[3][3] = 1;
normalize_m4(mat);
scale_m4_fl(scale, ss->cache->radius);
mul_m4_m4m4(tmat, scale, mat);
invert_m4_m4(mat, tmat);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test_cube(&test, vd.co, mat)) {
if (plane_point_side_flip(vd.co, sn, fc, flip)) {
float intr[3];
float val[3];
point_plane_project(intr, vd.co, sn, fc);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, ss->cache->radius*test.dist)*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float an[3];
float fc[3];
float offset = get_offset(sd, ss);
float displace;
int n;
float temp[3];
calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
displace = radius*offset;
mul_v3_v3v3(temp, an, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test_sq(&test, vd.co)) {
if (plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
}
BLI_pbvh_vertex_iter_end;
}
}
static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float an[3];
float fc[3];
float offset = get_offset(sd, ss);
float displace;
int n;
float temp[3];
calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
displace = -radius*offset;
mul_v3_v3v3(temp, an, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
float (*proxy)[3];
proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test_sq(&test, vd.co)) {
if (!plane_point_side(vd.co, an, fc)) {
float intr[3];
float val[3];
point_plane_project(intr, vd.co, an, fc);
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
mul_v3_v3fl(proxy[vd.i], val, fade);
if(vd.mvert)
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
}
BLI_pbvh_vertex_iter_end;
}
}
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
Mesh *me= (Mesh*)ob->data;
float (*ofs)[3]= NULL;
@@ -1475,36 +2325,27 @@ static void sculpt_update_keyblock(SculptSession *ss)
}
}
static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush)
{
SculptSearchSphereData data;
Brush *brush = paint_brush(&sd->paint);
PBVHNode **nodes= NULL;
int totnode;
PBVHNode **nodes = NULL;
int n, totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence */
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius * ss->cache->radius;
/* Build a list of all nodes that are potentially within the brush's
area of influence */
if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
data.original= 1;
BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data,
&nodes, &totnode);
if(cache->first_time)
copy_v3_v3(ss->cache->grab_active_location[ss->cache->symmetry], ss->cache->location);
else
copy_v3_v3(ss->cache->location, ss->cache->grab_active_location[ss->cache->symmetry]);
}
else {
BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data,
&nodes, &totnode);
}
data.radius_squared = ss->cache->radius_squared;
data.original = ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
if(totnode) {
if (totnode) {
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
sculpt_undo_push_node(ss, nodes[n]);
BLI_pbvh_node_mark_update(nodes[n]);
}
/* Apply one type of brush action */
switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
@@ -1513,6 +2354,12 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
case SCULPT_TOOL_SMOOTH:
do_smooth_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_CREASE:
do_crease_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
do_crease_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
do_pinch_brush(sd, ss, nodes, totnode);
break;
@@ -1522,57 +2369,244 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
case SCULPT_TOOL_GRAB:
do_grab_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
do_rotate_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
do_snake_hook_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
do_nudge_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
do_thumb_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
do_layer_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
do_flatten_clay_brush(sd, ss, nodes, totnode, 0);
do_flatten_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
do_flatten_clay_brush(sd, ss, nodes, totnode, 1);
do_clay_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_TUBES:
do_clay_tubes_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
do_fill_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_SCRAPE:
do_scrape_brush(sd, ss, nodes, totnode);
break;
}
if (brush->sculpt_tool != SCULPT_TOOL_SMOOTH && brush->autosmooth_factor > 0) {
if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*(1-ss->cache->pressure)*ss->cache->autosmooth_overlap);
}
else {
smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*ss->cache->autosmooth_overlap);
}
}
/* copy the modified vertices from mesh to the active key */
if(ss->kb)
mesh_to_key(ss->ob->data, ss->kb);
/* optimization: we could avoid copying new coords to keyblock at each */
/* stroke step if there are no modifiers due to pbvh is used for displaying */
/* so to increase speed we'll copy new coords to keyblock when stroke is done */
if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ss);
if(nodes)
MEM_freeN(nodes);
MEM_freeN(nodes);
}
}
static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
{
Brush *brush= paint_brush(&sd->paint);
PBVHNode** nodes;
int totnode;
int n;
BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
switch (brush->sculpt_tool) {
case SCULPT_TOOL_GRAB:
case SCULPT_TOOL_ROTATE:
case SCULPT_TOOL_THUMB:
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode* proxies;
int proxy_count;
float (*origco)[3];
origco= sculpt_undo_push_node(ss, nodes[n])->co;
BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
float val[3];
int p;
copy_v3_v3(val, origco[vd.i]);
for (p= 0; p < proxy_count; p++)
add_v3_v3(val, proxies[p].co[vd.i]);
sculpt_clip(sd, ss, vd.co, val);
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_free_proxies(nodes[n]);
}
break;
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_CLAY:
case SCULPT_TOOL_CLAY_TUBES:
case SCULPT_TOOL_CREASE:
case SCULPT_TOOL_BLOB:
case SCULPT_TOOL_FILL:
case SCULPT_TOOL_FLATTEN:
case SCULPT_TOOL_INFLATE:
case SCULPT_TOOL_NUDGE:
case SCULPT_TOOL_PINCH:
case SCULPT_TOOL_SCRAPE:
case SCULPT_TOOL_SNAKE_HOOK:
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for (n= 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode* proxies;
int proxy_count;
BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
float val[3];
int p;
copy_v3_v3(val, vd.co);
for (p= 0; p < proxy_count; p++)
add_v3_v3(val, proxies[p].co[vd.i]);
sculpt_clip(sd, ss, vd.co, val);
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_free_proxies(nodes[n]);
}
break;
case SCULPT_TOOL_SMOOTH:
case SCULPT_TOOL_LAYER:
default:
break;
}
if (nodes)
MEM_freeN(nodes);
}
//static int max_overlap_count(Sculpt *sd)
//{
// int count[3];
// int i, j;
//
// for (i= 0; i < 3; i++) {
// count[i] = sd->radial_symm[i];
//
// for (j= 0; j < 3; j++) {
// if (i != j && sd->flags & (SCULPT_SYMM_X<<i))
// count[i] *= 2;
// }
// }
//
// return MAX3(count[0], count[1], count[2]);
//}
/* Flip all the editdata across the axis/axes specified by symm. Used to
calculate multiple modifications to the mesh when symmetry is enabled. */
static void calc_brushdata_symm(StrokeCache *cache, const char symm)
static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, const char axis, const float angle, const float feather)
{
flip_coord(cache->location, cache->true_location, symm);
flip_coord(cache->view_normal_symmetry, cache->view_normal, symm);
flip_coord(cache->grab_delta_symmetry, cache->grab_delta, symm);
cache->symmetry= symm;
flip_coord(cache->view_normal, cache->true_view_normal, symm);
// XXX This reduces the length of the grab delta if it approaches the line of symmetry
// XXX However, a different approach appears to be needed
//if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
// float frac = 1.0f/max_overlap_count(sd);
// float reduce = (feather-frac)/(1-frac);
// printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
// if (frac < 1)
// mul_v3_fl(cache->grab_delta_symmetry, reduce);
//}
unit_m4(cache->symm_rot_mat);
unit_m4(cache->symm_rot_mat_inv);
rotate_m4(cache->symm_rot_mat, axis, angle);
rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
mul_m4_v3(cache->symm_rot_mat, cache->location);
mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
}
static void do_radial_symmetry(Sculpt *sd, SculptSession *ss, Brush *brush, const char symm, const int axis, const float feather)
{
int i;
for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
ss->cache->radial_symmetry_pass= i;
calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
do_brush_action(sd, ss, brush);
}
}
static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
{
Brush *brush = paint_brush(&sd->paint);
StrokeCache *cache = ss->cache;
const char symm = sd->flags & 7;
int i;
copy_v3_v3(cache->location, cache->true_location);
copy_v3_v3(cache->grab_delta_symmetry, cache->grab_delta);
cache->symmetry = 0;
cache->bstrength = brush_strength(sd, cache);
do_brush_action(sd, ss, cache);
float feather = calc_symmetry_feather(sd, ss->cache);
float accum = integrate_overlap(brush);
float overlap = (brush->flag & BRUSH_SPACE_ATTEN && brush->flag & BRUSH_SPACE && !(brush->flag & BRUSH_ANCHORED)) && (brush->spacing < 100) ? 1.0f/accum : 1; // spacing is integer percentage of radius, divide by 50 to get normalized diameter
for(i = 1; i <= symm; ++i) {
if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
calc_brushdata_symm(cache, i);
do_brush_action(sd, ss, cache);
ss->cache->autosmooth_overlap = overlap;
cache->bstrength= brush_strength(sd, cache, feather, overlap);
cache->symmetry= symm;
/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for(i = 0; i <= symm; ++i) {
if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
cache->mirror_symmetry_pass= i;
cache->radial_symmetry_pass= 0;
calc_brushdata_symm(sd, cache, i, 0, 0, feather);
do_brush_action(sd, ss, brush);
do_radial_symmetry(sd, ss, brush, i, 'X', feather);
do_radial_symmetry(sd, ss, brush, i, 'Y', feather);
do_radial_symmetry(sd, ss, brush, i, 'Z', feather);
}
}
cache->first_time = 0;
sculpt_combine_proxies(sd, ss);
cache->first_time= 0;
}
static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
@@ -1585,37 +2619,13 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
}
/* Need to allocate a bigger buffer for bigger brush size */
ss->texcache_side = brush->size * 2;
ss->texcache_side = 2*sculpt_get_brush_size(brush);
if(!ss->texcache || ss->texcache_side > ss->texcache_actual) {
ss->texcache = brush_gen_texture_cache(brush, brush->size);
ss->texcache = brush_gen_texture_cache(brush, sculpt_get_brush_size(brush));
ss->texcache_actual = ss->texcache_side;
}
}
/* Sculpt mode handles multires differently from regular meshes, but only if
it's the last modifier on the stack and it is not on the first level */
struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
{
ModifierData *md, *nmd;
for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
if(md->type == eModifierType_Multires) {
MultiresModifierData *mmd= (MultiresModifierData*)md;
/* Check if any of the modifiers after multires are active
* if not it can use the multires struct */
for(nmd= md->next; nmd; nmd= nmd->next)
if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
break;
if(!nmd && mmd->sculptlvl > 0)
return mmd;
}
}
return NULL;
}
void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
@@ -1682,16 +2692,32 @@ static char *sculpt_tool_name(Sculpt *sd)
return "Draw Brush"; break;
case SCULPT_TOOL_SMOOTH:
return "Smooth Brush"; break;
case SCULPT_TOOL_CREASE:
return "Crease Brush"; break;
case SCULPT_TOOL_BLOB:
return "Blob Brush"; break;
case SCULPT_TOOL_PINCH:
return "Pinch Brush"; break;
case SCULPT_TOOL_INFLATE:
return "Inflate Brush"; break;
case SCULPT_TOOL_GRAB:
return "Grab Brush"; break;
case SCULPT_TOOL_NUDGE:
return "Nudge Brush"; break;
case SCULPT_TOOL_THUMB:
return "Thumb Brush"; break;
case SCULPT_TOOL_LAYER:
return "Layer Brush"; break;
case SCULPT_TOOL_FLATTEN:
return "Flatten Brush"; break;
return "Flatten Brush"; break;
case SCULPT_TOOL_CLAY:
return "Clay Brush"; break;
case SCULPT_TOOL_CLAY_TUBES:
return "Clay Tubes Brush"; break;
case SCULPT_TOOL_FILL:
return "Fill Brush"; break;
case SCULPT_TOOL_SCRAPE:
return "Scrape Brush"; break;
default:
return "Sculpting"; break;
}
@@ -1769,20 +2795,119 @@ static void sculpt_cache_free(StrokeCache *cache)
MEM_freeN(cache);
}
int sculpt_get_brush_size(Brush *brush)
{
return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? U.sculpt_paint_unified_size : brush->size;
}
void sculpt_set_brush_size(Brush *brush, int size)
{
if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE)
U.sculpt_paint_unified_size = size;
else
brush->size = size;
}
int sculpt_get_lock_brush_size(Brush *brush)
{
return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (U.sculpt_paint_settings & SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE) : (brush->flag & BRUSH_LOCK_SIZE);
}
float sculpt_get_brush_unprojected_radius(Brush *brush)
{
return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? U.sculpt_paint_unified_unprojected_radius : brush->unprojected_radius;
}
void sculpt_set_brush_unprojected_radius(Brush *brush, float unprojected_radius)
{
if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE)
U.sculpt_paint_unified_unprojected_radius = unprojected_radius;
else
brush->unprojected_radius = unprojected_radius;
}
float sculpt_get_brush_alpha(Brush *brush)
{
return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? U.sculpt_paint_unified_alpha : brush->alpha;
}
void sculpt_set_brush_alpha(Brush *brush, float alpha)
{
if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_ALPHA)
U.sculpt_paint_unified_alpha = alpha;
else
brush->alpha = alpha;
}
/* Initialize the stroke cache invariants from operator properties */
static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bContext *C, wmOperator *op)
static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSession *ss, wmOperator *op, wmEvent *event)
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
Brush *brush = paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
Object *ob= CTX_data_active_object(C);
ModifierData *md;
int i;
int mode;
ss->cache = cache;
RNA_float_get_array(op->ptr, "scale", cache->scale);
cache->flag = RNA_int_get(op->ptr, "flag");
RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance);
RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
/* Set scaling adjustment */
ss->cache->scale[0] = 1.0f / ob->size[0];
ss->cache->scale[1] = 1.0f / ob->size[1];
ss->cache->scale[2] = 1.0f / ob->size[2];
ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
/* Initialize mirror modifier clipping */
ss->cache->flag = 0;
for(md= ob->modifiers.first; md; md= md->next) {
if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
const MirrorModifierData *mmd = (MirrorModifierData*) md;
/* Mark each axis that needs clipping along with its tolerance */
if(mmd->flag & MOD_MIR_CLIPPING) {
ss->cache->flag |= CLIP_X << mmd->axis;
if(mmd->tolerance > ss->cache->clip_tolerance[mmd->axis])
ss->cache->clip_tolerance[mmd->axis] = mmd->tolerance;
}
}
}
/* Initial mouse location */
if (event) {
ss->cache->initial_mouse[0] = event->x;
ss->cache->initial_mouse[1] = event->y;
}
else {
ss->cache->initial_mouse[0] = 0;
ss->cache->initial_mouse[1] = 0;
}
mode = RNA_int_get(op->ptr, "mode");
cache->invert = mode == WM_BRUSHSTROKE_INVERT;
cache->alt_smooth = mode == WM_BRUSHSTROKE_SMOOTH;
/* Alt-Smooth */
if (ss->cache->alt_smooth) {
Paint *p= &sd->paint;
Brush *br;
int i;
BLI_strncpy(cache->saved_active_brush_name, brush->id.name+2, sizeof(cache->saved_active_brush_name));
for(i = 0; i < p->brush_count; ++i) {
br = p->brushes[i];
if (strcmp(br->id.name+2, "Smooth")==0) {
paint_brush_set(p, br);
brush = br;
break;
}
}
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
@@ -1790,11 +2915,13 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
viewvector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if(brush->sculpt_tool == SCULPT_TOOL_LAYER) {
/* not supported yet for multires */
@@ -1820,69 +2947,143 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
cache->original = 1;
}
if(ELEM3(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE))
if(ELEM7(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES))
if(!(brush->flag & BRUSH_ACCUMULATE))
cache->original = 1;
cache->rotation = 0;
cache->first_time = 1;
cache->special_rotation = (brush->flag & BRUSH_RAKE) ? sd->last_angle : 0;
//cache->last_rake[0] = sd->last_x;
//cache->last_rake[1] = sd->last_y;
cache->first_time= 1;
cache->vertex_rotation= 0;
}
/* Initialize the stroke cache variants from operator properties */
static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
int dx, dy;
if(!(brush->flag & BRUSH_ANCHORED) || cache->first_time)
//RNA_float_get_array(ptr, "location", cache->traced_location);
if (cache->first_time ||
!((brush->flag & BRUSH_ANCHORED)||
(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK)||
(brush->sculpt_tool == SCULPT_TOOL_ROTATE))
)
{
RNA_float_get_array(ptr, "location", cache->true_location);
cache->flip = RNA_boolean_get(ptr, "flip");
}
cache->pen_flip = RNA_boolean_get(ptr, "pen_flip");
RNA_float_get_array(ptr, "mouse", cache->mouse);
cache->pressure = RNA_float_get(ptr, "pressure");
/* Truly temporary data that isn't stored in properties */
sd->draw_pressure= 1;
sd->pressure_value= cache->pressure;
cache->previous_pixel_radius = cache->pixel_radius;
cache->pixel_radius = brush->size;
cache->pixel_radius = sculpt_get_brush_size(brush);
if(cache->first_time)
cache->initial_radius = unproject_brush_radius(ss->ob, cache->vc, cache->true_location, brush->size);
if(cache->first_time) {
if (!sculpt_get_lock_brush_size(brush)) {
cache->initial_radius= unproject_brush_radius(ss->ob, cache->vc, cache->true_location, sculpt_get_brush_size(brush));
sculpt_set_brush_unprojected_radius(brush, cache->initial_radius);
}
else {
cache->initial_radius= sculpt_get_brush_unprojected_radius(brush);
}
if(brush->flag & BRUSH_SIZE_PRESSURE && brush->sculpt_tool != SCULPT_TOOL_GRAB) {
if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
cache->initial_radius *= 2.0f;
}
if(brush->flag & BRUSH_SIZE_PRESSURE) {
cache->pixel_radius *= cache->pressure;
cache->radius = cache->initial_radius * cache->pressure;
cache->radius= cache->initial_radius * cache->pressure;
}
else
cache->radius = cache->initial_radius;
cache->radius= cache->initial_radius;
if(!(brush->flag & BRUSH_ANCHORED))
cache->radius_squared = cache->radius*cache->radius;
if(!(brush->flag & BRUSH_ANCHORED || ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) {
copy_v2_v2(cache->tex_mouse, cache->mouse);
if ( (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
(brush->flag & BRUSH_RANDOM_ROTATION) &&
!(brush->flag & BRUSH_RAKE))
{
cache->special_rotation = 2*M_PI*BLI_frand();
}
}
if(brush->flag & BRUSH_ANCHORED) {
int hit = 0;
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
cache->pixel_radius = sqrt(dx*dx + dy*dy);
cache->radius = unproject_brush_radius(ss->ob, paint_stroke_view_context(stroke),
cache->true_location, cache->pixel_radius);
cache->rotation = atan2(dy, dx);
sd->anchored_size = cache->pixel_radius = sqrt(dx*dx + dy*dy);
cache->special_rotation = atan2(dx, dy) + M_PI;
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
float d[3];
float halfway[3];
float out[3];
d[0] = dx;
d[1] = dy;
d[2] = 0;
mul_v3_v3fl(halfway, d, 0.5f);
add_v3_v3(halfway, cache->initial_mouse);
if (sculpt_stroke_get_location(C, stroke, out, halfway)) {
copy_v3_v3(sd->anchored_location, out);
copy_v3_v3(sd->anchored_initial_mouse, halfway);
copy_v2_v2(cache->tex_mouse, halfway);
copy_v3_v3(cache->true_location, sd->anchored_location);
sd->anchored_size /= 2.0f;
cache->pixel_radius /= 2.0f;
hit = 1;
}
}
if (!hit)
copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
cache->radius= unproject_brush_radius(ss->ob, paint_stroke_view_context(stroke), cache->true_location, cache->pixel_radius);
cache->radius_squared = cache->radius*cache->radius;
copy_v3_v3(sd->anchored_location, cache->true_location);
sd->draw_anchored = 1;
}
else if(brush->flag & BRUSH_RAKE) {
int update;
const float u = 0.5f;
const float v = 1 - u;
const float r = 20;
dx = cache->last_rake[0] - cache->mouse[0];
dy = cache->last_rake[1] - cache->mouse[1];
const float dx = cache->last_rake[0] - cache->mouse[0];
const float dy = cache->last_rake[1] - cache->mouse[1];
update = dx*dx + dy*dy > 100;
if (cache->first_time) {
copy_v3_v3(cache->last_rake, cache->mouse);
}
else if (dx*dx + dy*dy >= r*r) {
cache->special_rotation = atan2(dx, dy);
/* To prevent jitter, only update the angle if the mouse has moved over 10 pixels */
if(update && !cache->first_time)
cache->rotation = M_PI_2 + atan2(dy, dx);
if(update || cache->first_time) {
cache->last_rake[0] = cache->mouse[0];
cache->last_rake[1] = cache->mouse[1];
cache->last_rake[0] = u*cache->last_rake[0] + v*cache->mouse[0];
cache->last_rake[1] = u*cache->last_rake[1] + v*cache->mouse[1];
}
}
@@ -1900,16 +3101,123 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct P
/* compute delta to move verts by */
if(!cache->first_time) {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
float delta[3];
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ss->ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
mul_mat3_m4_v3(imat, delta);
add_v3_v3(cache->grab_delta, delta);
}
else {
zero_v3(cache->grab_delta);
}
copy_v3_v3(cache->old_grab_location, grab_location);
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
sd->draw_anchored = 1;
copy_v3_v3(sd->anchored_location, cache->true_location);
copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
sd->anchored_size = cache->pixel_radius;
}
/* Find the nudge/clay tubes delta */
else if(brush->sculpt_tool == SCULPT_TOOL_NUDGE || brush->sculpt_tool == SCULPT_TOOL_CLAY_TUBES) {
float grab_location[3], imat[4][4];
if(cache->first_time)
copy_v3_v3(cache->orig_grab_location, cache->true_location);
/* compute 3d coordinate at same z from original location + mouse */
initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
cache->orig_grab_location[1], cache->orig_grab_location[2]);
window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
/* compute delta to move verts by */
if (!cache->first_time) {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ss->ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
}
else {
zero_v3(cache->grab_delta);
}
copy_v3_v3(cache->old_grab_location, grab_location);
}
/* Find the snake hook delta */
else if(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) {
float grab_location[3], imat[4][4];
if(cache->first_time)
copy_v3_v3(cache->orig_grab_location, cache->true_location);
else
add_v3_v3(cache->true_location, cache->grab_delta);
/* compute 3d coordinate at same z from original location + mouse */
initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
cache->orig_grab_location[1], cache->orig_grab_location[2]);
window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
/* compute delta to move verts by */
if (!cache->first_time) {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ss->ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
}
else {
zero_v3(cache->grab_delta);
}
copy_v3_v3(cache->old_grab_location, grab_location);
}
/* Find the thumb delta */
else if(brush->sculpt_tool == SCULPT_TOOL_THUMB) {
float grab_location[3], imat[4][4];
if(cache->first_time)
copy_v3_v3(cache->orig_grab_location, cache->true_location);
/* compute 3d coordinate at same z from original location + mouse */
initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
cache->orig_grab_location[1], cache->orig_grab_location[2]);
window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
/* compute delta to move verts by */
if (!cache->first_time) {
float delta[3];
sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ss->ob->obmat);
mul_mat3_m4_v3(imat, delta);
add_v3_v3(cache->grab_delta, delta);
}
else {
zero_v3(cache->grab_delta);
}
copy_v3_v3(cache->old_grab_location, grab_location);
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
sd->draw_anchored = 1;
copy_v3_v3(sd->anchored_location, cache->orig_grab_location);
copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
sd->anchored_size = cache->pixel_radius;
}
else if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
cache->vertex_rotation = -atan2(dx, dy) / 4.0f;
sd->draw_anchored = 1;
copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
copy_v3_v3(sd->anchored_location, cache->true_location);
sd->anchored_size = cache->pixel_radius;
}
sd->special_rotation = cache->special_rotation;
}
static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss)
@@ -1930,19 +3238,23 @@ typedef struct {
int original;
} SculptRaycastData;
void sculpt_raycast_cb(PBVHNode *node, void *data_v)
void sculpt_raycast_cb(PBVHNode *node, void *data_v, float* tmin)
{
SculptRaycastData *srd = data_v;
float (*origco)[3]= NULL;
if (BLI_pbvh_node_get_tmin(node) < *tmin) {
SculptRaycastData *srd = data_v;
float (*origco)[3]= NULL;
if(srd->original && srd->ss->cache) {
/* intersect with coordinates from before we started stroke */
SculptUndoNode *unode= sculpt_undo_get_node(srd->ss, node);
origco= (unode)? unode->co: NULL;
if(srd->original && srd->ss->cache) {
/* intersect with coordinates from before we started stroke */
SculptUndoNode *unode= sculpt_undo_get_node(node);
origco= (unode)? unode->co: NULL;
}
if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
srd->hit = 1;
*tmin = srd->dist;
}
}
srd->hit |= BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco,
srd->ray_start, srd->ray_normal, &srd->dist);
}
/* Do a raycast in the tree to find the 3d brush location
@@ -1956,10 +3268,12 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou
StrokeCache *cache= ss->cache;
float ray_start[3], ray_end[3], ray_normal[3], dist;
float obimat[4][4];
float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
mouse[1] - vc->ar->winrct.ymin};
float mval[2];
SculptRaycastData srd;
mval[0] = mouse[0] - vc->ar->winrct.xmin;
mval[1] = mouse[1] - vc->ar->winrct.ymin;
sculpt_stroke_modifiers_check(C, ss);
viewline(vc->ar, vc->v3d, mval, ray_start, ray_end);
@@ -1987,43 +3301,6 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou
return srd.hit;
}
/* Initialize stroke operator properties */
static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
{
Object *ob= CTX_data_active_object(C);
ModifierData *md;
float scale[3], clip_tolerance[3] = {0,0,0};
float mouse[2];
int flag = 0;
/* Set scaling adjustment */
scale[0] = 1.0f / ob->size[0];
scale[1] = 1.0f / ob->size[1];
scale[2] = 1.0f / ob->size[2];
RNA_float_set_array(op->ptr, "scale", scale);
/* Initialize mirror modifier clipping */
for(md= ob->modifiers.first; md; md= md->next) {
if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
const MirrorModifierData *mmd = (MirrorModifierData*) md;
/* Mark each axis that needs clipping along with its tolerance */
if(mmd->flag & MOD_MIR_CLIPPING) {
flag |= CLIP_X << mmd->axis;
if(mmd->tolerance > clip_tolerance[mmd->axis])
clip_tolerance[mmd->axis] = mmd->tolerance;
}
}
}
RNA_int_set(op->ptr, "flag", flag);
RNA_float_set_array(op->ptr, "clip_tolerance", clip_tolerance);
/* Initial mouse location */
mouse[0] = event->x;
mouse[1] = event->y;
RNA_float_set_array(op->ptr, "initial_mouse", mouse);
}
static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
{
Scene *scene= CTX_data_scene(C);
@@ -2051,22 +3328,26 @@ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
int i;
/* Restore the mesh before continuing with anchored stroke */
if(brush->flag & BRUSH_ANCHORED) {
if((brush->flag & BRUSH_ANCHORED) ||
(brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_SIZE_PRESSURE)) ||
(brush->flag & BRUSH_RESTORE_MESH))
{
StrokeCache *cache = ss->cache;
int i;
PBVHNode **nodes;
int n, totnode;
BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
//#pragma omp parallel for private(n) schedule(static)
#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
SculptUndoNode *unode;
unode= sculpt_undo_get_node(ss, nodes[n]);
unode= sculpt_undo_get_node(nodes[n]);
if(unode) {
PBVHVertexIter vd;
@@ -2074,8 +3355,12 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
copy_v3_v3(vd.co, unode->co[vd.i]);
if(vd.no) VECCOPY(vd.no, unode->no[vd.i])
else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_mark_update(nodes[n]);
}
}
@@ -2096,7 +3381,6 @@ static void sculpt_flush_update(bContext *C)
SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
int redraw = 0;
if(mmd)
multires_mark_as_modified(ob);
@@ -2109,14 +3393,22 @@ static void sculpt_flush_update(bContext *C)
rcti r;
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r);
if(redraw) {
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
//rcti tmp;
r.xmin += ar->winrct.xmin + 1;
r.xmax += ar->winrct.xmin - 1;
r.ymin += ar->winrct.ymin + 1;
r.ymax += ar->winrct.ymin - 1;
//tmp = r;
//if (!BLI_rcti_is_empty(&ss->previous_r))
// BLI_union_rcti(&r, &ss->previous_r);
//ss->previous_r= tmp;
ss->partial_redraw = 1;
ED_region_tag_redraw_partial(ar, &r);
}
@@ -2127,9 +3419,12 @@ static void sculpt_flush_update(bContext *C)
or over the background (0) */
static int over_mesh(bContext *C, struct wmOperator *op, float x, float y)
{
float mouse[2] = {x, y}, co[3];
return (int)sculpt_stroke_get_location(C, op->customdata, co, mouse);
float mouse[2], co[3];
mouse[0] = x;
mouse[1] = y;
return sculpt_stroke_get_location(C, op->customdata, co, mouse);
}
static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
@@ -2143,11 +3438,22 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
sculpt_brush_stroke_init_properties(C, op, event, ss);
sculpt_update_cache_invariants(C, sd, ss, op, event);
sculpt_update_cache_invariants(sd, ss, C, op);
sculpt_undo_push_begin(sculpt_tool_name(sd));
sculpt_undo_push_begin(ss, sculpt_tool_name(sd));
#ifdef _OPENMP
/* If using OpenMP then create a number of threads two times the
number of processor cores.
Justification: Empirically I've found that two threads per
processor gives higher throughput. */
if (sd->flags & SCULPT_USE_OPENMP) {
int num_procs;
num_procs = omp_get_num_procs();
omp_set_num_threads(2*num_procs);
}
#endif
return 1;
}
@@ -2161,7 +3467,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
SculptSession *ss = CTX_data_active_object(C)->sculpt;
sculpt_stroke_modifiers_check(C, ss);
sculpt_update_cache_variants(sd, ss, stroke, itemptr);
sculpt_update_cache_variants(C, sd, ss, stroke, itemptr);
sculpt_restore_mesh(sd, ss);
do_symmetrical_brush_actions(sd, ss);
@@ -2169,19 +3475,43 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
sculpt_flush_update(C);
}
static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused)
{
Object *ob= CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
(void)unused;
// reset values used to draw brush after completing the stroke
sd->draw_anchored= 0;
sd->draw_pressure= 0;
sd->special_rotation= 0;
/* Finished */
if(ss->cache) {
sculpt_stroke_modifiers_check(C, ss);
/* Alt-Smooth */
if (ss->cache->alt_smooth) {
Paint *p= &sd->paint;
Brush *br;
int i;
for(i = 0; i < p->brush_count; ++i) {
br = p->brushes[i];
if (strcmp(br->id.name+2, ss->cache->saved_active_brush_name)==0) {
paint_brush_set(p, br);
break;
}
}
}
sculpt_cache_free(ss->cache);
ss->cache = NULL;
sculpt_undo_push_end(ss);
sculpt_undo_push_end();
BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
@@ -2218,6 +3548,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
/* For tablet rotation */
ignore_background_click = RNA_boolean_get(op->ptr,
"ignore_background_click");
if(ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
paint_stroke_free(stroke);
return OPERATOR_PASS_THROUGH;
@@ -2242,7 +3573,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
sculpt_stroke_update_step, sculpt_stroke_done);
sculpt_update_cache_invariants(sd, ss, C, op);
sculpt_update_cache_invariants(C, sd, ss, op, NULL);
paint_stroke_exec(C, op);
@@ -2254,7 +3585,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
ot->flag |= OPTYPE_REGISTER;
static EnumPropertyItem stroke_mode_items[] = {
{ WM_BRUSHSTROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally" },
{ WM_BRUSHSTROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke" },
{ WM_BRUSHSTROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke" },
{ 0 }
};
/* identifiers */
ot->name= "Sculpt Mode";
@@ -2265,36 +3601,32 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
ot->modal= paint_stroke_modal;
ot->exec= sculpt_brush_stroke_exec;
ot->poll= sculpt_poll;
/* flags (sculpt does own undo? (ton) */
ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
ot->flag= OPTYPE_BLOCKING;
/* properties */
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
/* If the object has a scaling factor, brushes also need to be scaled
to work as expected. */
RNA_def_float_vector(ot->srna, "scale", 3, NULL, 0.0f, FLT_MAX, "Scale", "", 0.0f, 1000.0f);
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement,
"Stroke", "");
RNA_def_int(ot->srna, "flag", 0, 0, INT_MAX, "flag", "", 0, INT_MAX);
/* For mirror modifiers */
RNA_def_float_vector(ot->srna, "clip_tolerance", 3, NULL, 0.0f, FLT_MAX, "clip_tolerance", "", 0.0f, 1000.0f);
/* The initial 2D location of the mouse */
RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
RNA_def_enum(ot->srna, "mode", stroke_mode_items, WM_BRUSHSTROKE_NORMAL,
"Sculpt Stroke Mode",
"Action taken when a sculpt stroke is made");
RNA_def_boolean(ot->srna, "ignore_background_click", 0,
"Ignore Background Click",
"Clicks on the background don't start the stroke");
"Clicks on the background do not start the stroke");
}
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
static int sculpt_set_persistent_base(bContext *C, wmOperator *op)
static int sculpt_set_persistent_base(bContext *C, wmOperator *unused)
{
SculptSession *ss = CTX_data_active_object(C)->sculpt;
(void)unused;
if(ss) {
if(ss->layer_co)
MEM_freeN(ss->layer_co);
@@ -2314,7 +3646,7 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->exec= sculpt_set_persistent_base;
ot->poll= sculpt_mode_poll;
ot->flag= OPTYPE_REGISTER;
ot->flag= 0;//OPTYPE_REGISTER;
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -2322,18 +3654,21 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void sculpt_init_session(Scene *scene, Object *ob)
{
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->ob = ob;
sculpt_update_mesh_elements(scene, ob, 0);
}
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
int flush_recalc= 0;
(void)unused;
/* multires in sculpt mode could have different from object mode subdivision level */
flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* if object has got active modifiers, it's dm could be different in sculpt mode */
@@ -2359,9 +3694,13 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
/* Create persistent sculpt mode data */
if(!ts->sculpt)
if(!ts->sculpt) {
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
/* Turn on X plane mirror symmetry by default */
ts->sculpt->flags |= SCULPT_SYMM_X;
}
/* Create sculpt mode session data */
if(ob->sculpt)
free_sculptsession(ob);
@@ -2388,7 +3727,7 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->exec= sculpt_toggle_mode;
ot->poll= ED_operator_object_active;
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
ot->flag= 0;
}
void ED_operatortypes_sculpt()

View File

@@ -32,6 +32,9 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
#include "DNA_key_types.h"
#include "BLI_pbvh.h"
struct bContext;
struct Brush;
@@ -65,8 +68,49 @@ void sculpt_stroke_free(struct SculptStroke *);
void sculpt_stroke_add_point(struct SculptStroke *, const short x, const short y);
void sculpt_stroke_apply(struct Sculpt *sd, struct SculptStroke *);
void sculpt_stroke_apply_all(struct Sculpt *sd, struct SculptStroke *);
int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]);
/* Partial Mesh Visibility */
void sculptmode_pmv(int mode);
/* Undo */
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
char idname[MAX_ID_NAME]; /* name instead of pointer*/
void *node; /* only during push, not valid afterwards! */
float (*co)[3];
short (*no)[3];
int totvert;
/* non-multires */
int maxvert; /* to verify if totvert it still the same */
int *index; /* to restore into right location */
/* multires */
int maxgrid; /* same for grid */
int gridsize; /* same for grid */
int totgrid; /* to restore into right location */
int *grids; /* to restore into right location */
/* layer brush */
float *layer_disp;
/* shape keys */
char *shapeName[32]; /* keep size in sync with keyblock dna */
} SculptUndoNode;
SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
void sculpt_undo_push_begin(char *name);
void sculpt_undo_push_end(void);
struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
int sculpt_modifiers_active(Scene *scene, Object *ob);
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos);
#endif

View File

@@ -0,0 +1,302 @@
/*
* $Id: sculpt.c 29425 2010-06-12 15:05:19Z jwilkins $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
* Implements the Sculpt Mode tools
*
*/
#include "BLI_math.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_key_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_mesh.h"
#include "BKE_key.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_sculpt.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
/************************** Undo *************************/
static void update_cb(PBVHNode *node, void *unused)
{
(void)unused;
BLI_pbvh_node_mark_update(node);
}
static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
MVert *mvert;
MultiresModifierData *mmd;
int *index;
int i, j, update= 0;
sculpt_update_mesh_elements(scene, ob, 0);
for(unode=lb->first; unode; unode=unode->next) {
if(!(strcmp(unode->idname, ob->id.name)==0))
continue;
if(unode->maxvert) {
char *shapeName= (char*)unode->shapeName;
/* regular mesh restore */
if(ss->totvert != unode->maxvert)
continue;
if (ss->kb && strcmp(ss->kb->name, shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key= ob_get_key(ob);
KeyBlock *kb= key_get_named_keyblock(key, shapeName);
if (kb) {
ob->shapenr= BLI_findindex(&key->block, kb) + 1;
ob->shapeflag|= OB_SHAPE_LOCK;
sculpt_update_mesh_elements(scene, ob, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
} else {
/* key has been removed -- skip this undo node */
continue;
}
}
index= unode->index;
mvert= ss->mvert;
if (ss->kb) {
float (*vertCos)[3];
vertCos= key_to_vertcos(ob, ss->kb);
for(i=0; i<unode->totvert; i++)
swap_v3_v3(vertCos[index[i]], unode->co[i]);
/* propagate new coords to keyblock */
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
MEM_freeN(vertCos);
} else {
for(i=0; i<unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->co[i]);
mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else if(unode->maxgrid && dm->getGridData) {
/* multires restore */
DMGridData **grids, *grid;
float (*co)[3];
int gridsize;
if(dm->getNumGrids(dm) != unode->maxgrid)
continue;
if(dm->getGridSize(dm) != unode->gridsize)
continue;
grids= dm->getGridData(dm);
gridsize= dm->getGridSize(dm);
co = unode->co;
for(j=0; j<unode->totgrid; j++) {
grid= grids[unode->grids[j]];
for(i=0; i<gridsize*gridsize; i++, co++)
swap_v3_v3(grid[i].co, co[0]);
}
}
update= 1;
}
if(update) {
/* we update all nodes still, should be more clever, but also
needs to work correct when exiting/entering sculpt mode and
the nodes get recreated, though in that case it could do all */
BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, NULL);
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
if((mmd=sculpt_multires_active(scene, ob)))
multires_mark_as_modified(ob);
if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
}
}
static void sculpt_undo_free(ListBase *lb)
{
SculptUndoNode *unode;
for(unode=lb->first; unode; unode=unode->next) {
if(unode->co)
MEM_freeN(unode->co);
if(unode->no)
MEM_freeN(unode->no);
if(unode->index)
MEM_freeN(unode->index);
if(unode->grids)
MEM_freeN(unode->grids);
if(unode->layer_disp)
MEM_freeN(unode->layer_disp);
}
}
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
if(!lb)
return NULL;
for(unode=lb->first; unode; unode=unode->next)
if(unode->node == node)
return unode;
return NULL;
}
SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
Object *ob= ss->ob;
SculptUndoNode *unode;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
/* list is manipulated by multiple threads, so we lock */
BLI_lock_thread(LOCK_CUSTOM1);
if((unode= sculpt_undo_get_node(node))) {
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
strcpy(unode->idname, ob->id.name);
unode->node= node;
BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
&maxgrid, &gridsize, NULL, NULL);
unode->totvert= totvert;
/* we will use this while sculpting, is mapalloc slow to access then? */
unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
BLI_addtail(lb, unode);
if(maxgrid) {
/* multires */
unode->maxgrid= maxgrid;
unode->totgrid= totgrid;
unode->gridsize= gridsize;
unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
}
else {
/* regular mesh */
unode->maxvert= ss->totvert;
unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
}
BLI_unlock_thread(LOCK_CUSTOM1);
/* copy threaded, hopefully this is the performance critical part */
{
PBVHVertexIter vd;
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
}
BLI_pbvh_vertex_iter_end;
}
if(unode->grids)
memcpy(unode->grids, grids, sizeof(int)*totgrid);
/* store active shape key */
if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
else unode->shapeName[0]= '\0';
return unode;
}
void sculpt_undo_push_begin(char *name)
{
undo_paint_push_begin(UNDO_PAINT_MESH, name,
sculpt_undo_restore, sculpt_undo_free);
}
void sculpt_undo_push_end(void)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
/* we don't need normals in the undo stack */
for(unode=lb->first; unode; unode=unode->next) {
if(unode->no) {
MEM_freeN(unode->no);
unode->no= NULL;
}
if(unode->layer_disp) {
MEM_freeN(unode->layer_disp);
unode->layer_disp= NULL;
}
}
undo_paint_push_end(UNDO_PAINT_MESH);
}

View File

@@ -792,7 +792,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
uiLayoutSetContextPointer(layout, "edit_image", &imaptr);
if(!compact)
uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);
uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL, NULL);
// XXX missing: reload, pack

View File

@@ -4278,7 +4278,7 @@ static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C)
{
uiLayout *row, *col;
uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL);
uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, NULL);
if (!RNA_pointer_get(ptr, "sound").data)
{
uiItemL(layout, "Select a sound from the list or load a new one", 0);

View File

@@ -237,7 +237,7 @@ static void nla_panel_animdata (const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row= uiLayoutRow(layout, 1);
uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/); // XXX: need to make these operators
uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/, NULL); // XXX: need to make these operators
/* extrapolation */
row= uiLayoutRow(layout, 1);

View File

@@ -81,7 +81,7 @@
void node_buts_group(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
uiTemplateIDBrowse(layout, C, ptr, "nodetree", NULL, NULL, "");
uiTemplateIDBrowse(layout, C, ptr, "nodetree", NULL, NULL, "", NULL);
}
static void node_buts_value(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -306,7 +306,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA
bNode *node= ptr->data;
uiLayout *col;
uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL);
uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, NULL);
if(!node->id) return;
@@ -467,7 +467,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
PointerRNA imaptr;
PropertyRNA *prop;
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, NULL);
if(!node->id) return;
@@ -504,7 +504,7 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
const char *layer_name;
char scene_name[19];
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, NULL);
if(!node->id) return;
@@ -1204,7 +1204,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *C, PointerRNA *pt
static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, NULL);
}
static void node_texture_buts_output(uiLayout *layout, bContext *C, PointerRNA *ptr)

View File

@@ -69,6 +69,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
#include "gpu_buffers.h"
#include "smoke_API.h"

View File

@@ -130,7 +130,7 @@ typedef struct PreviewImage {
unsigned int w[2];
unsigned int h[2];
short changed[2];
short pad0, pad1;
short changed_timestamp[2];
unsigned int * rect[2];
} PreviewImage;

View File

@@ -33,9 +33,9 @@
#include "DNA_ID.h"
#include "DNA_texture_types.h"
#ifndef MAX_MTEX
#define MAX_MTEX 18
#endif
//#ifndef MAX_MTEX // XXX Not used?
//#define MAX_MTEX 18
//#endif
struct CurveMapping;
struct MTex;
@@ -43,8 +43,8 @@ struct Image;
typedef struct BrushClone {
struct Image *image; /* image for clone tool */
float offset[2]; /* offset of clone image from canvas */
float alpha, pad; /* transparency for drawing of clone image */
float offset[2]; /* offset of clone image from canvas */
float alpha, pad; /* transparency for drawing of clone image */
} BrushClone;
typedef struct Brush {
@@ -53,50 +53,94 @@ typedef struct Brush {
struct BrushClone clone;
struct CurveMapping *curve; /* falloff curve */
struct MTex mtex;
short flag, blend; /* general purpose flag, blend mode */
int size; /* brush diameter */
float jitter; /* jitter the position of the brush */
float spacing; /* spacing of paint operations */
int smooth_stroke_radius; /* turning radius (in pixels) for smooth stroke */
float smooth_stroke_factor; /* higher values limit fast changes in the stroke direction */
float rate; /* paint operations / second (airbrush) */
struct Image *image_icon;
float rgb[3]; /* color */
float alpha; /* opacity */
float normal_weight;
char sculpt_tool; /* active sculpt tool */
short blend, pad; /* blend mode */
int size; /* brush diameter */
int flag; /* general purpose flag */
float jitter; /* jitter the position of the brush */
int spacing; /* spacing of paint operations */
int smooth_stroke_radius; /* turning radius (in pixels) for smooth stroke */
float smooth_stroke_factor; /* higher values limit fast changes in the stroke direction */
float rate; /* paint operations / second (airbrush) */
float rgb[3]; /* color */
float alpha; /* opacity */
int sculpt_plane; /* the direction of movement for sculpt vertices */
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
char sculpt_tool; /* active sculpt tool */
char vertexpaint_tool; /* active vertex/weight paint tool/blend mode */
char imagepaint_tool; /* active image paint tool */
char pad2;
char pad3;
float autosmooth_factor;
float crease_pinch_factor;
float plane_trim;
float texture_sample_bias;
int texture_overlay_alpha;
float unprojected_radius;
float add_col[3];
float sub_col[3];
} Brush;
/* Brush.flag */
#define BRUSH_AIRBRUSH 1
#define BRUSH_TORUS 2
#define BRUSH_ALPHA_PRESSURE 4
#define BRUSH_SIZE_PRESSURE 8
#define BRUSH_JITTER_PRESSURE 16 /* was BRUSH_RAD_PRESSURE */
#define BRUSH_SPACING_PRESSURE 32
#define BRUSH_FIXED_TEX 64
#define BRUSH_RAKE 128
#define BRUSH_ANCHORED 256
#define BRUSH_DIR_IN 512
#define BRUSH_SPACE 1024
#define BRUSH_SMOOTH_STROKE 2048
#define BRUSH_PERSISTENT 4096
#define BRUSH_ACCUMULATE 8192
#define BRUSH_LOCK_ALPHA 16384
#define BRUSH_AIRBRUSH (1<<0)
#define BRUSH_TORUS (1<<1)
#define BRUSH_ALPHA_PRESSURE (1<<2)
#define BRUSH_SIZE_PRESSURE (1<<3)
#define BRUSH_JITTER_PRESSURE (1<<4) /* was BRUSH_RAD_PRESSURE */
#define BRUSH_SPACING_PRESSURE (1<<5)
#define BRUSH_FIXED_TEX (1<<6)
#define BRUSH_RAKE (1<<7)
#define BRUSH_ANCHORED (1<<8)
#define BRUSH_DIR_IN (1<<9)
#define BRUSH_SPACE (1<<10)
#define BRUSH_SMOOTH_STROKE (1<<11)
#define BRUSH_PERSISTENT (1<<12)
#define BRUSH_ACCUMULATE (1<<13)
#define BRUSH_LOCK_ALPHA (1<<14)
#define BRUSH_ORIGINAL_NORMAL (1<<15)
#define BRUSH_OFFSET_PRESSURE (1<<16)
#define BRUSH_SPACE_ATTEN (1<<18)
#define BRUSH_ADAPTIVE_SPACE (1<<19)
#define BRUSH_LOCK_SIZE (1<<20)
#define BRUSH_TEXTURE_OVERLAY (1<<21)
#define BRUSH_EDGE_TO_EDGE (1<<22)
#define BRUSH_RESTORE_MESH (1<<23)
#define BRUSH_INVERSE_SMOOTH_PRESSURE (1<<24)
#define BRUSH_RANDOM_ROTATION (1<<25)
#define BRUSH_PLANE_TRIM (1<<26)
#define BRUSH_FRONTFACE (1<<27)
/* Brush.sculpt_tool */
#define SCULPT_TOOL_DRAW 1
#define SCULPT_TOOL_SMOOTH 2
#define SCULPT_TOOL_PINCH 3
#define SCULPT_TOOL_INFLATE 4
#define SCULPT_TOOL_GRAB 5
#define SCULPT_TOOL_LAYER 6
#define SCULPT_TOOL_FLATTEN 7
#define SCULPT_TOOL_CLAY 8
#define SCULPT_TOOL_DRAW 1
#define SCULPT_TOOL_SMOOTH 2
#define SCULPT_TOOL_PINCH 3
#define SCULPT_TOOL_INFLATE 4
#define SCULPT_TOOL_GRAB 5
#define SCULPT_TOOL_LAYER 6
#define SCULPT_TOOL_FLATTEN 7
#define SCULPT_TOOL_CLAY 8
#define SCULPT_TOOL_FILL 9
#define SCULPT_TOOL_SCRAPE 10
#define SCULPT_TOOL_NUDGE 11
#define SCULPT_TOOL_THUMB 12
#define SCULPT_TOOL_SNAKE_HOOK 13
#define SCULPT_TOOL_ROTATE 14
//#define SCULPT_TOOL_WAX 15 // XXX: reuse this slot later
#define SCULPT_TOOL_CREASE 16
#define SCULPT_TOOL_BLOB 17
#define SCULPT_TOOL_CLAY_TUBES 18
/* ImagePaintSettings.tool */
#define PAINT_TOOL_DRAW 0
@@ -104,5 +148,16 @@ typedef struct Brush {
#define PAINT_TOOL_SMEAR 2
#define PAINT_TOOL_CLONE 3
/* direction that the brush displaces along */
enum {
SCULPT_DISP_DIR_AREA,
SCULPT_DISP_DIR_VIEW,
SCULPT_DISP_DIR_X,
SCULPT_DISP_DIR_Y,
SCULPT_DISP_DIR_Z,
};
#define MAX_BRUSH_PIXEL_RADIUS 200
#endif

View File

@@ -64,7 +64,8 @@ typedef struct CurveMap {
typedef struct CurveMapping {
int flag, cur; /* cur; for buttons, to show active curve */
int preset, pad;
int preset;
int changed_timestamp;
rctf curr, clipr; /* current rect, clip rect (is default rect too) */
@@ -87,7 +88,9 @@ typedef enum CurveMappingPreset {
CURVE_PRESET_SHARP,
CURVE_PRESET_SMOOTH,
CURVE_PRESET_MAX,
CURVE_PRESET_MID9
CURVE_PRESET_MID9,
CURVE_PRESET_ROUND,
CURVE_PRESET_ROOT,
} CurveMappingPreset;
/* histogram->mode */

View File

@@ -569,12 +569,30 @@ typedef struct Sculpt {
Paint paint;
/* For rotating around a pivot point */
float pivot[3];
//float pivot[3]; XXX not used?
int flags;
/* Control tablet input */
char tablet_size, tablet_strength;
char pad[6];
//char tablet_size, tablet_strength; XXX not used?
int radial_symm[3];
// all this below is used to communicate with the cursor drawing routine
/* record movement of mouse so that rake can start at an intuitive angle */
float last_x, last_y;
float last_angle;
int draw_anchored;
int anchored_size;
float anchored_location[3];
float anchored_initial_mouse[2];
int draw_pressure;
float pressure_value;
float special_rotation;
int pad;
} Sculpt;
typedef struct VPaint {
@@ -1105,19 +1123,22 @@ typedef struct Scene {
/* Paint.flags */
typedef enum {
PAINT_SHOW_BRUSH = 1,
PAINT_FAST_NAVIGATE = 2
PAINT_SHOW_BRUSH = (1<<0),
PAINT_FAST_NAVIGATE = (1<<1),
PAINT_SHOW_BRUSH_ON_SURFACE = (1<<2),
} PaintFlags;
/* Sculpt.flags */
/* These can eventually be moved to paint flags? */
typedef enum SculptFlags {
SCULPT_SYMM_X = 1,
SCULPT_SYMM_Y = 2,
SCULPT_SYMM_Z = 4,
SCULPT_LOCK_X = 64,
SCULPT_LOCK_Y = 128,
SCULPT_LOCK_Z = 256
SCULPT_SYMM_X = (1<<0),
SCULPT_SYMM_Y = (1<<1),
SCULPT_SYMM_Z = (1<<2),
SCULPT_LOCK_X = (1<<3),
SCULPT_LOCK_Y = (1<<4),
SCULPT_LOCK_Z = (1<<5),
SCULPT_SYMMETRY_FEATHER = (1<<6),
SCULPT_USE_OPENMP = (1<<7),
} SculptFlags;
/* ImagePaintSettings.flag */

View File

@@ -341,9 +341,10 @@ typedef struct UserDef {
short gp_settings;
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
short sculpt_paint_settings; /* user preferences for sculpt and paint */
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
short textimeout,texcollectrate;
short wmdrawmethod, wmpad;
short wmdrawmethod; /* removed wmpad */
int memcachelimit;
int prefetchframes;
short frameserverport;
@@ -373,6 +374,11 @@ typedef struct UserDef {
short autokey_flag; /* flags for autokeying */
struct ColorBand coba_weight; /* from texture.h */
int sculpt_paint_unified_size; /* unified radius of brush in pixels */
float sculpt_paint_unified_unprojected_radius;/* unified radius of brush in Blender units */
float sculpt_paint_unified_alpha; /* unified strength of brush */
float sculpt_paint_overlay_col[3];
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
@@ -524,6 +530,11 @@ extern UserDef U; /* from blenkernel blender.c */
#define GP_PAINT_DOSMOOTH (1<<0)
#define GP_PAINT_DOSIMPLIFY (1<<1)
/* sculpt_paint_settings */
#define SCULPT_PAINT_USE_UNIFIED_SIZE (1<<0)
#define SCULPT_PAINT_USE_UNIFIED_ALPHA (1<<1)
#define SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE (1<<2)
/* color picker types */
#define USER_CP_CIRCLE 0
#define USER_CP_SQUARE_SV 1

View File

@@ -307,8 +307,7 @@ typedef struct wmOperator {
typedef enum wmRadialControlMode {
WM_RADIALCONTROL_SIZE,
WM_RADIALCONTROL_STRENGTH,
WM_RADIALCONTROL_ANGLE
WM_RADIALCONTROL_ANGLE,
} wmRadialControlMode;
#endif /* DNA_WINDOWMANAGER_TYPES_H */

View File

@@ -45,7 +45,6 @@ if env['WITH_BF_GAMEENGINE']:
if env['BF_UNIT_TEST']:
defs.append('UNIT_TEST')
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'

View File

@@ -52,6 +52,7 @@ INCLUDE_DIRECTORIES(
../../gpu
../../imbuf
../../render/extern/include
../../../../extern/glew/include
. )
FILE(GLOB INC_FILES ../*.h ../../makesdna/*.h)

View File

@@ -30,6 +30,7 @@
#include "DNA_brush_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -51,6 +52,58 @@ static void rna_Brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_BRUSH|NA_EDITED, br);
}
static int rna_Brush_is_sculpt_brush(Brush *me, bContext *C)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
int i;
for (i= 0; i < sd->paint.brush_count; i++) {
if (strcmp(me->id.name+2, sd->paint.brushes[i]->id.name+2) == 0)
return 1;
}
return 0;
}
static int rna_Brush_is_vpaint_brush(Brush *me, bContext *C)
{
VPaint *vp = CTX_data_tool_settings(C)->vpaint;
int i;
for (i= 0; i < vp->paint.brush_count; i++) {
if (strcmp(me->id.name+2, vp->paint.brushes[i]->id.name+2) == 0)
return 1;
}
return 0;
}
static int rna_Brush_is_wpaint_brush(Brush *me, bContext *C)
{
VPaint *vp = CTX_data_tool_settings(C)->wpaint;
int i;
for (i= 0; i < vp->paint.brush_count; i++) {
if (strcmp(me->id.name+2, vp->paint.brushes[i]->id.name+2) == 0)
return 1;
}
return 0;
}
static int rna_Brush_is_imapaint_brush(Brush *me, bContext *C)
{
ImagePaintSettings *data = &(CTX_data_tool_settings(C)->imapaint);
int i;
for (i= 0; i < data->paint.brush_count; i++) {
if (strcmp(me->id.name+2, data->paint.brushes[i]->id.name+2) == 0)
return 1;
}
return 0;
}
#else
static void rna_def_brush_texture_slot(BlenderRNA *brna)
@@ -100,14 +153,42 @@ static void rna_def_brush(BlenderRNA *brna)
static EnumPropertyItem brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", 0, "Draw", ""},
{SCULPT_TOOL_SMOOTH, "SMOOTH", 0, "Smooth", ""},
{SCULPT_TOOL_CREASE, "CREASE", 0, "Crease", ""},
{SCULPT_TOOL_BLOB, "BLOB", 0, "Blob", ""},
{SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", ""},
{SCULPT_TOOL_INFLATE, "INFLATE", 0, "Inflate", ""},
{SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", 0, "Snake Hook", ""},
{SCULPT_TOOL_ROTATE, "ROTATE", 0, "Rotate", ""},
{SCULPT_TOOL_THUMB, "THUMB", 0, "Thumb", ""},
{SCULPT_TOOL_NUDGE, "NUDGE", 0, "Nudge", ""},
{SCULPT_TOOL_LAYER, "LAYER", 0, "Layer", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", 0, "Flatten", ""},
{SCULPT_TOOL_CLAY, "CLAY", 0, "Clay", ""},
//{SCULPT_TOOL_CLAY_TUBES, "CLAY_TUBES", 0, "Clay Tubes", ""}, XXX: remove clay tubes from UI
{SCULPT_TOOL_FILL, "FILL", 0, "Fill", ""},
{SCULPT_TOOL_SCRAPE, "SCRAPE", 0, "Scrape", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem brush_stroke_method_items[] = {
{0, "DOTS", 0, "Dots", ""},
{BRUSH_RESTORE_MESH, "DRAG_DOT", 0, "Drag Dot", ""},
{BRUSH_SPACE, "SPACE", 0, "Space", ""},
{BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", ""},
{BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem texture_angle_source_items[] = {
{0, "USER", 0, "User", ""},
{BRUSH_RAKE, "RAKE", 0, "Rake", ""},
{BRUSH_RANDOM_ROTATION, "RANDOM", 0, "Random", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem texture_angle_source_no_random_items[] = {
{0, "USER", 0, "User", ""},
{BRUSH_RAKE, "RAKE", 0, "Rake", ""},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem brush_vertexpaint_tool_items[] = {
{0, "MIX", 0, "Mix", "Use mix blending mode while painting"},
{1, "ADD", 0, "Add", "Use add blending mode while painting"},
@@ -129,11 +210,76 @@ static void rna_def_brush(BlenderRNA *brna)
{0, "ADD", 0, "Add", "Add effect of brush"},
{BRUSH_DIR_IN, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_flatten_contrast_items[]= {
{0, "FLATTEN", 0, "Flatten", "Add effect of brush"},
{BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_fill_deepen_items[]= {
{0, "FILL", 0, "Fill", "Add effect of brush"},
{BRUSH_DIR_IN, "DEEPEN", 0, "Deepen", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_scrape_peaks_items[]= {
{0, "SCRAPE", 0, "Scrape", "Add effect of brush"},
{BRUSH_DIR_IN, "PEAKS", 0, "Peaks", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_pinch_magnify_items[]= {
{0, "PINCH", 0, "Pinch", "Add effect of brush"},
{BRUSH_DIR_IN, "MAGNIFY", 0, "Magnify", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static const EnumPropertyItem prop_inflate_deflate_items[]= {
{0, "INFLATE", 0, "Inflate", "Add effect of brush"},
{BRUSH_DIR_IN, "DEFLATE", 0, "Deflate", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem brush_sculpt_plane_items[] = {
{SCULPT_DISP_DIR_AREA, "AREA", 0, "Area Plane", ""},
{SCULPT_DISP_DIR_VIEW, "VIEW", 0, "View Plane", ""},
{SCULPT_DISP_DIR_X, "X", 0, "X Plane", ""},
{SCULPT_DISP_DIR_Y, "Y", 0, "Y Plane", ""},
{SCULPT_DISP_DIR_Z, "Z", 0, "Z Plane", ""},
{0, NULL, 0, NULL, NULL}};
FunctionRNA *func;
PropertyRNA *parm;
srna= RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
/* functions */
func= RNA_def_function(srna, "is_sculpt_brush", "rna_Brush_is_sculpt_brush");
RNA_def_function_ui_description(func, "Returns true if Brush can be used for sculpting");
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_boolean(func, "ret", 0, "", "");
RNA_def_function_return(func, parm);
func= RNA_def_function(srna, "is_vpaint_brush", "rna_Brush_is_vpaint_brush");
RNA_def_function_ui_description(func, "Returns true if Brush can be used for vertex painting");
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_boolean(func, "ret", 0, "", "");
RNA_def_function_return(func, parm);
func= RNA_def_function(srna, "is_wpaint_brush", "rna_Brush_is_wpaint_brush");
RNA_def_function_ui_description(func, "Returns true if Brush can be used for weight painting");
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_boolean(func, "ret", 0, "", "");
RNA_def_function_return(func, parm);
func= RNA_def_function(srna, "is_imapaint_brush", "rna_Brush_is_imapaint_brush");
RNA_def_function_ui_description(func, "Returns true if Brush can be used for image painting");
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_boolean(func, "ret", 0, "", "");
RNA_def_function_return(func, parm);
/* enums */
prop= RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_blend_items);
@@ -144,7 +290,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_enum_items(prop, brush_sculpt_tool_items);
RNA_def_property_ui_text(prop, "Sculpt Tool", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "vertexpaint_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_vertexpaint_tool_items);
RNA_def_property_ui_text(prop, "Vertex/Weight Paint Tool", "");
@@ -158,33 +304,94 @@ static void rna_def_brush(BlenderRNA *brna)
prop= RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_flip_direction_items);
RNA_def_property_ui_text(prop, "Direction", "Mapping type to use for this image in the game engine");
RNA_def_property_ui_text(prop, "Direction", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "stroke_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, brush_stroke_method_items);
RNA_def_property_ui_text(prop, "Stroke Method", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "texture_angle_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, texture_angle_source_items);
RNA_def_property_ui_text(prop, "Texture Angle Source", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "texture_angle_source_no_random", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, texture_angle_source_no_random_items);
RNA_def_property_ui_text(prop, "Texture Angle Source", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "flatten_contrast", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_flatten_contrast_items);
RNA_def_property_ui_text(prop, "Flatten/Contrast", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "inflate_deflate", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_inflate_deflate_items);
RNA_def_property_ui_text(prop, "Inflate/Deflate", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "fill_deepen", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_fill_deepen_items);
RNA_def_property_ui_text(prop, "Fill/Deepen", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "scrape_peaks", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_scrape_peaks_items);
RNA_def_property_ui_text(prop, "Scrape/Peaks", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "pinch_magnify", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_pinch_magnify_items);
RNA_def_property_ui_text(prop, "Pinch/Magnify", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "sculpt_plane", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_sculpt_plane_items);
RNA_def_property_ui_text(prop, "Sculpt Plane", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* number values */
prop= RNA_def_property(srna, "size", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, 200);
RNA_def_property_ui_text(prop, "Size", "Diameter of the brush");
prop= RNA_def_property(srna, "size", PROP_INT, PROP_DISTANCE);
RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS*10);
RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 1, 0);
RNA_def_property_ui_text(prop, "Size", "Radius of the brush in pixels");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1, 0, 0);
RNA_def_property_ui_text(prop, "Surface Size", "Radius of brush in Blender units");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "jitter");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Jitter", "Jitter the position of the brush while painting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "spacing", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "spacing");
RNA_def_property_range(prop, 1.0f, 100.0f);
RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush stamps");
prop= RNA_def_property(srna, "spacing", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "spacing");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_range(prop, 1, 500, 5, 0);
RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_NONE);
prop= RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_DISTANCE);
RNA_def_property_range(prop, 10, 200);
RNA_def_property_ui_text(prop, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "smooth_stroke_factor", PROP_FLOAT, PROP_NONE);
prop= RNA_def_property(srna, "smooth_stroke_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.5, 0.99);
RNA_def_property_ui_text(prop, "Smooth Stroke Factor", "Higher values give a smoother stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -202,10 +409,56 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
RNA_def_property_ui_text(prop, "Strength", "How powerful the effect of the brush is when applied");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "plane_offset", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "plane_offset");
RNA_def_property_float_default(prop, 0);
RNA_def_property_range(prop, -2.0f, 2.0f);
RNA_def_property_ui_range(prop, -0.5f, 0.5f, 0.001, 0.001);
RNA_def_property_ui_text(prop, "Plane Offset", "Adjusts plane on which the brush acts towards or away from the object surface");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "plane_trim", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "plane_trim");
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0, 1.0f);
RNA_def_property_ui_text(prop, "Plane Trim", "If a vertex is further from offset plane than this then it is not affected");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "texture_sample_bias", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "texture_sample_bias");
RNA_def_property_float_default(prop, 0);
RNA_def_property_range(prop, -1, 1);
RNA_def_property_ui_text(prop, "Texture Sample Bias", "Value added to texture samples");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "normal_weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "normal_weight");
RNA_def_property_float_default(prop, 0);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Strength", "The amount of pressure on the brush");
RNA_def_property_ui_text(prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "crease_pinch_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "crease_pinch_factor");
RNA_def_property_float_default(prop, 2.0f/3.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "autosmooth_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
RNA_def_property_float_default(prop, 0);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
RNA_def_property_ui_text(prop, "Autosmooth", "Amount of smoothing to automatically apply to each stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* flag */
@@ -214,6 +467,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Airbrush", "Keep applying paint effect while holding mouse (spray)");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_original_normal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_NORMAL);
RNA_def_property_ui_text(prop, "Original Normal", "When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_wrap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TORUS);
RNA_def_property_ui_text(prop, "Wrap", "Enable torus wrapping while painting");
@@ -225,6 +483,12 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_offset_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_OFFSET_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Plane Offset Pressure", "Enable tablet pressure sensitivity for offset");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_size_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SIZE_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
@@ -243,11 +507,32 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_inverse_smooth_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERSE_SMOOTH_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Inverse Smooth Pressure", "Lighter pressure causes more smoothing to be applied");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RAKE);
RNA_def_property_ui_text(prop, "Rake", "Rotate the brush texture to match the stroke direction");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_random_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RANDOM_ROTATION);
RNA_def_property_ui_text(prop, "Random Rotation", "Rotate the brush texture at random");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM);
RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_frontface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FRONTFACE);
RNA_def_property_ui_text(prop, "Use Front-Face", "Brush only affects vertexes that face the viewer");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_anchor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ANCHORED);
RNA_def_property_ui_text(prop, "Anchored", "Keep the brush anchored to the initial location");
@@ -273,6 +558,37 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Accumulate", "Accumulate stroke dabs on top of each other");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_space_atten", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE_ATTEN);
RNA_def_property_ui_text(prop, "Use Automatic Strength Adjustment", "Automatically adjusts strength to give consistent results for different spacings");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* adaptive space is not implemented yet */
prop= RNA_def_property(srna, "use_adaptive_space", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ADAPTIVE_SPACE);
RNA_def_property_ui_text(prop, "Adaptive Spacing", "Space daubs according to surface orientation instead of screen space");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "lock_brush_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LOCK_SIZE);
RNA_def_property_ui_text(prop, "Use Blender Units", "When locked brush stays same size relative to object; when unlocked brush size is given in pixels");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "use_texture_overlay", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TEXTURE_OVERLAY);
RNA_def_property_ui_text(prop, "Use Texture Overlay", "Show texture in viewport");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "edge_to_edge", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_EDGE_TO_EDGE);
RNA_def_property_ui_text(prop, "Edge-to-edge", "Drag anchor brush from edge-to-edge");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "restore_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RESTORE_MESH);
RNA_def_property_ui_text(prop, "Restore Mesh", "Allows a single dot to be carefully positioned");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* not exposed in the interface yet
prop= RNA_def_property(srna, "fixed_tex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FIXED_TEX);
@@ -303,6 +619,31 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
prop= RNA_def_property(srna, "texture_overlay_alpha", PROP_INT, PROP_PERCENTAGE);
RNA_def_property_int_sdna(prop, NULL, "texture_overlay_alpha");
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Texture Overlay Alpha", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "add_col", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "add_col");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "sub_col", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "sub_col");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Subract Color", "Color of cursor when subtracting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "image_icon", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "image_icon");
RNA_def_property_struct_type(prop, "Image");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Image Icon", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* clone tool */
prop= RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clone.image");
@@ -357,16 +698,19 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Pressure", "Tablet pressure");
prop= RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_ui_text(prop, "Flip", "");
// used in uv painting
prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_ui_text(prop, "Time", "");
prop= RNA_def_property(srna, "flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_ui_text(prop, "Flip", "");
/* XXX: Tool (this will be for pressing a modifier key for a different brush,
e.g. switching to a Smooth brush in the middle of the stroke */
// XXX: i don't think blender currently supports the ability to properly do a remappable modifier in the middle of a stroke
}
void RNA_def_brush(BlenderRNA *brna)

View File

@@ -213,6 +213,12 @@ static int rna_Image_depth_get(PointerRNA *ptr)
return depth;
}
static int rna_Image_is_image_icon(Image *me, bContext *C)
{
const char prefix[] = ".imageicon.";
return strncmp(me->id.name+2, prefix, sizeof(prefix)-1) == 0;
}
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -292,6 +298,9 @@ static void rna_def_image(BlenderRNA *brna)
{IMA_STD_FIELD, "ODD", 0, "Lower First", "Lower field first"},
{0, NULL, 0, NULL, NULL}};
FunctionRNA *func;
PropertyRNA *parm;
srna= RNA_def_struct(brna, "Image", "ID");
RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image");
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
@@ -333,6 +342,14 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Field Order", "Order of video fields. Select which lines are displayed first");
RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL);
/* functions */
func= RNA_def_function(srna, "is_image_icon", "rna_Image_is_image_icon");
RNA_def_function_ui_description(func, "Returns true if Image name is prefixed with .imageicon.");
parm= RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_boolean(func, "ret", 0, "", "");
RNA_def_function_return(func, parm);
/* booleans */
prop= RNA_def_property(srna, "fields", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);

View File

@@ -193,7 +193,7 @@ static void rna_Paint_active_brush_name_get(PointerRNA *ptr, char *value)
Paint *p= ptr->data;
Brush *br = paint_brush(p);
BLI_strncpy(value, br->id.name+2, sizeof(br->id.name-2));
BLI_strncpy(value, br->id.name+2, sizeof(br->id.name)-2);
}
@@ -212,7 +212,7 @@ static void rna_Paint_active_brush_name_set(PointerRNA *ptr, const char *value)
for(i = 0; i < p->brush_count; ++i) {
br = p->brushes[i];
if (strcmp(br->id.name+2, value)==0) {
paint_brush_set(p, br);
return;
@@ -262,6 +262,10 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH);
RNA_def_property_ui_text(prop, "Show Brush", "");
prop= RNA_def_property(srna, "show_brush_on_surface", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH_ON_SURFACE);
RNA_def_property_ui_text(prop, "Show Brush On Surface", "");
prop= RNA_def_property(srna, "fast_navigate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_FAST_NAVIGATE);
RNA_def_property_ui_text(prop, "Fast Navigate", "For multires, show low resolution while navigating the view");
@@ -274,7 +278,14 @@ static void rna_def_sculpt(BlenderRNA *brna)
srna= RNA_def_struct(brna, "Sculpt", "Paint");
RNA_def_struct_ui_text(srna, "Sculpt", "");
prop= RNA_def_property(srna, "radial_symm", PROP_INT, PROP_XYZ);
RNA_def_property_int_sdna(prop, NULL, "radial_symm");
RNA_def_property_int_default(prop, 1);
RNA_def_property_range(prop, 1, 64);
RNA_def_property_ui_range(prop, 0, 32, 1, 1);
RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis", "Number of times to copy strokes across the surface");
prop= RNA_def_property(srna, "symmetry_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMM_X);
RNA_def_property_ui_text(prop, "Symmetry X", "Mirror brush across the X axis");
@@ -298,6 +309,14 @@ static void rna_def_sculpt(BlenderRNA *brna)
prop= RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Z);
RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices");
prop= RNA_def_property(srna, "use_symmetry_feather", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMMETRY_FEATHER);
RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical daubs");
prop= RNA_def_property(srna, "use_openmp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_USE_OPENMP);
RNA_def_property_ui_text(prop, "Use OpenMP", "Take advantage of multiple CPU cores to improve sculpting performance");
}
static void rna_def_vertex_paint(BlenderRNA *brna)

View File

@@ -274,6 +274,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
RNA_def_string(func, "filter", "", 0, "", "Function identifier to filter the ID block.");
func= RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -281,6 +282,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
RNA_def_string(func, "filter", "", 0, "", "Function identifier to filter the ID block.");
RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);

View File

@@ -32,6 +32,7 @@
#include "DNA_curve_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_brush_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -867,7 +868,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Transform", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_edge(srna);
rna_def_userdef_theme_spaces_face(srna);
@@ -2194,7 +2195,43 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "gp_eraser");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
/* sculpt and paint */
prop= RNA_def_property(srna, "sculpt_paint_overlay_col", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "sculpt_paint_overlay_col");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Sculpt/Paint Overlay Color", "Color of texture overlay");
prop= RNA_def_property(srna, "sculpt_paint_use_unified_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_USE_UNIFIED_SIZE);
RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Radius", "Instead of per brush radius, the radius is shared across brushes");
prop= RNA_def_property(srna, "sculpt_paint_use_unified_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_USE_UNIFIED_ALPHA);
RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Strength", "Instead of per brush strength, the strength is shared across brushes");
prop= RNA_def_property(srna, "sculpt_paint_unified_lock_brush_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE);
RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Blender Units", "When locked all brushes stay same size relative to object; when unlocked all brush sizes are given in pixels");
prop= RNA_def_property(srna, "sculpt_paint_unified_size", PROP_INT, PROP_DISTANCE);
RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS*10);
RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 1, 0);
RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Size", "Unified radius of the brush in pixels");
prop= RNA_def_property(srna, "sculpt_paint_unified_unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1, 0, 0);
RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Surface Size", "Unified radius of brush in Blender units");
prop= RNA_def_property(srna, "sculpt_paint_unified_strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "sculpt_paint_unified_alpha");
RNA_def_property_float_default(prop, 0.5f);
RNA_def_property_range(prop, 0.0f, 10.0f);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Strength", "Unified power of effect of brushes when applied");
/* duplication linking */
prop= RNA_def_property(srna, "duplicate_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_MESH);

View File

@@ -24,7 +24,7 @@ if env['WITH_BF_COLLADA']:
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
incs += ' ../../../extern/binreloc/include'
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
@@ -35,4 +35,4 @@ if env['WITH_GHOST_COCOA']:
if env['BF_BUILDINFO']:
defs.append('NAN_BUILDINFO')
env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defs, libtype=['core'], priority=[5] )
env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )

View File

@@ -389,6 +389,7 @@ static void wm_draw_triple_free(wmWindow *win)
wmDrawTriple *triple= win->drawdata;
glDeleteTextures(triple->nx*triple->ny, triple->bind);
MEM_freeN(triple);
win->drawdata= NULL;
@@ -560,7 +561,8 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
else {
win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
if(!wm_triple_gen_textures(win, win->drawdata)) {
if(!wm_triple_gen_textures(win, win->drawdata))
{
wm_draw_triple_fail(C, win);
return;
}

View File

@@ -61,6 +61,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
#include "BKE_utildefines.h"
#include "BKE_brush.h" // JW
#include "BIF_gl.h"
#include "BIF_glutil.h" /* for paint cursor */
@@ -69,6 +70,7 @@
#include "ED_screen.h"
#include "ED_util.h"
#include "ED_view3d.h" // JW
#include "RNA_access.h"
#include "RNA_define.h"
@@ -2595,19 +2597,28 @@ typedef struct wmRadialControl {
GLuint tex;
} wmRadialControl;
extern Paint *paint_get_active(Scene *sce);
extern struct Brush *paint_brush(struct Paint *paint);
static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
{
wmRadialControl *rc = (wmRadialControl*)customdata;
ARegion *ar = CTX_wm_region(C);
float r1=0.0f, r2=0.0f, r3=0.0f, angle=0.0f;
/* Keep cursor in the original place */
x = rc->initial_mouse[0] - ar->winrct.xmin;
y = rc->initial_mouse[1] - ar->winrct.ymin;
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
glPushMatrix();
glTranslatef((float)x, (float)y, 0.0f);
ViewContext vc;
int hit = 0;
int flip;
int sign;
float* col;
const float str = rc->mode == WM_RADIALCONTROL_STRENGTH ? (rc->value + 0.5) : (brush->texture_overlay_alpha / 100.0f);
if(rc->mode == WM_RADIALCONTROL_SIZE) {
r1= rc->value;
@@ -2615,29 +2626,37 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
r3= r1;
} else if(rc->mode == WM_RADIALCONTROL_STRENGTH) {
r1= (1 - rc->value) * WM_RADIAL_CONTROL_DISPLAY_SIZE;
r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
r2= r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
} else if(rc->mode == WM_RADIALCONTROL_ANGLE) {
r1= r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
r1= r2= r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
angle = rc->value;
}
glColor4ub(255, 255, 255, 128);
glEnable( GL_LINE_SMOOTH );
/* Keep cursor in the original place */
x = rc->initial_mouse[0] - ar->winrct.xmin;
y = rc->initial_mouse[1] - ar->winrct.ymin;
view3d_set_viewcontext(C, &vc);
// XXX: no way currently to know state of pen flip or invert key modifier without starting a stroke
flip = 1;
sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1);
if (sign < 0 && ELEM4(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH))
col = brush->sub_col;
else
col = brush->add_col;
glTranslatef((float)x, (float)y, 0.0f);
glEnable(GL_BLEND);
if(rc->mode == WM_RADIALCONTROL_ANGLE)
fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
if(rc->tex) {
const float str = rc->mode == WM_RADIALCONTROL_STRENGTH ? (rc->value + 0.5) : 1;
if(rc->mode == WM_RADIALCONTROL_ANGLE) {
glRotatef(angle, 0, 0, 1);
fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
}
if(rc->mode == WM_RADIALCONTROL_ANGLE) {
glRotatef(angle, 0, 0, 1);
}
if (rc->tex) {
glBindTexture(GL_TEXTURE_2D, rc->tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -2645,7 +2664,7 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glColor4f(0,0,0, str);
glColor4f(U.sculpt_paint_overlay_col[0],U.sculpt_paint_overlay_col[1],U.sculpt_paint_overlay_col[2], str);
glTexCoord2f(0,0);
glVertex2f(-r3, -r3);
glTexCoord2f(1,0);
@@ -2658,11 +2677,20 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
glDisable(GL_TEXTURE_2D);
}
glColor4ub(255, 255, 255, 128);
if(rc->mode == WM_RADIALCONTROL_ANGLE) {
glColor4f(col[0], col[1], col[2], 0.5f);
glEnable(GL_LINE_SMOOTH);
glRotatef(-angle, 0, 0, 1);
fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
glRotatef(angle, 0, 0, 1);
fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
glDisable(GL_LINE_SMOOTH);
}
glColor4f(col[0], col[1], col[2], 0.5f);
glutil_draw_lined_arc(0.0, M_PI*2.0, r1, 40);
glutil_draw_lined_arc(0.0, M_PI*2.0, r2, 40);
glDisable(GL_BLEND);
glDisable( GL_LINE_SMOOTH );
glPopMatrix();
}
@@ -2674,6 +2702,7 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
float dist;
double new_value = RNA_float_get(op->ptr, "new_value");
int ret = OPERATOR_RUNNING_MODAL;
float initial_value = RNA_float_get(op->ptr, "initial_value");
mode = RNA_int_get(op->ptr, "mode");
RNA_int_get_array(op->ptr, "initial_mouse", initial_mouse);
@@ -2682,6 +2711,16 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
case MOUSEMOVE:
delta[0]= initial_mouse[0] - event->x;
delta[1]= initial_mouse[1] - event->y;
//if (mode == WM_RADIALCONTROL_SIZE)
// delta[0]+= initial_value;
//else if(mode == WM_RADIALCONTROL_STRENGTH)
// delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - initial_value);
//else if(mode == WM_RADIALCONTROL_ANGLE) {
// delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value*M_PI/180.0f);
// delta[1]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value*M_PI/180.0f);
//}
dist= sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
if(mode == WM_RADIALCONTROL_SIZE)
@@ -2728,6 +2767,11 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(CTX_wm_region(C));
//if (ret != OPERATOR_RUNNING_MODAL) {
// wmWindow *win = CTX_wm_window(C);
// WM_cursor_restore(win);
//}
return ret;
}
@@ -2735,10 +2779,15 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
wmRadialControl *rc = MEM_callocN(sizeof(wmRadialControl), "radial control");
wmWindow *win = CTX_wm_window(C);
int mode = RNA_int_get(op->ptr, "mode");
float initial_value = RNA_float_get(op->ptr, "initial_value");
//float initial_size = RNA_float_get(op->ptr, "initial_size");
int mouse[2] = {event->x, event->y};
//if (initial_size == 0)
// initial_size = WM_RADIAL_CONTROL_DISPLAY_SIZE;
if(mode == WM_RADIALCONTROL_SIZE) {
rc->max_value = 200;
mouse[0]-= initial_value;
@@ -2775,6 +2824,8 @@ int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
rc->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), op->type->poll,
wm_radial_control_paint, op->customdata);
//WM_cursor_modal(win, CURSOR_NONE);
/* add modal handler */
WM_event_add_modal_handler(C, op);

View File

@@ -36,12 +36,14 @@
struct ARegion;
struct ARegionType;
struct Base;
struct Brush;
struct bNodeTree;
struct CSG_FaceIteratorDescriptor;
struct CSG_VertexIteratorDescriptor;
struct ColorBand;
struct CurveMapping;
struct EditBone;
struct EditFace;
struct EditMesh;
struct ID;
struct FCurve;
@@ -54,16 +56,20 @@ struct LOD_Decimation_Info;
struct MTex;
struct Main;
struct Material;
struct MCol;
struct MenuType;
struct Mesh;
struct ModifierData;
struct MultiresModifierData;
struct NodeBlurData;
struct Object;
struct PBVHNode;
struct Render;
struct RenderEngine;
struct RenderLayer;
struct RenderResult;
struct ScrArea;
struct SculptSession;
struct ShadeInput;
struct ShadeResult;
struct SpaceImage;
@@ -375,6 +381,24 @@ void smoke_get_index(void) {return;}
void smoke_step(void) {return;}
*/
/* sculpt */
/*
void ED_sculpt_force_update(struct bContext *C) {}
struct SculptUndoNode *sculpt_undo_push_node(struct SculptSession *ss, struct PBVHNode *node) {return (struct SculptUndoNode *)NULL;}
void sculpt_undo_push_end(void) {}
void sculpt_undo_push_begin(char *name) {}
struct SculptUndoNode *sculpt_undo_get_node(struct PBVHNode *node) {return (struct SculptUndoNode *) NULL;}
struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob) {return (struct MultiresModifierData *) NULL;}
int sculpt_modifiers_active(struct Scene *scene, struct Object *ob) {return 0;}
*/
int sculpt_get_brush_size(struct Brush *brush) {return 0;}
void sculpt_set_brush_size(struct Brush *brush, int size) {}
int sculpt_get_lock_brush_size(struct Brush *brush){ return 0;}
float sculpt_get_brush_unprojected_radius(struct Brush *brush){return 0.0f;}
void sculpt_set_brush_unprojected_radius(struct Brush *brush, float unprojected_radius){}
float sculpt_get_brush_alpha(struct Brush *brush){return 0.0f;}
void sculpt_set_brush_alpha(struct Brush *brush, float alpha){}
char blender_path[] = "";
/* CSG */