Sculpt:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 25 Nov 2009 17:51:16 +0000 (17:51 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 25 Nov 2009 17:51:16 +0000 (17:51 +0000)
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r24483:24889

39 files changed:
1  2 
release/scripts/ui/properties_data_modifier.py
release/scripts/ui/properties_physics_softbody.py
release/scripts/ui/properties_render.py
release/scripts/ui/space_console.py
release/scripts/ui/space_sequencer.py
release/scripts/ui/space_view3d.py
release/scripts/ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/CCGSubSurf.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/paint.c
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_matrix.c
source/blender/blenlib/intern/math_vector.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/object/object_modifier.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/windowmanager/intern/wm_files.c

@@@ -196,231 -257,378 +257,382 @@@ class DATA_PT_modifiers(DataButtonsPane
          split = layout.split()
  
          col = split.column()
-         col.itemR(md, "use_edge_angle", text="Edge Angle")
+         col.prop(md, "midlevel")
+         if wide_ui:
+             col = split.column()
+         col.prop(md, "strength")
+     def EDGE_SPLIT(self, layout, ob, md, wide_ui):
+         split = layout.split()
+         col = split.column()
+         col.prop(md, "use_edge_angle", text="Edge Angle")
          sub = col.column()
          sub.active = md.use_edge_angle
-         sub.itemR(md, "split_angle")
+         sub.prop(md, "split_angle")
+         if wide_ui:
+             col = split.column()
+         col.prop(md, "use_sharp", text="Sharp Edges")
+     def EXPLODE(self, layout, ob, md, wide_ui):
+         split = layout.split()
  
          col = split.column()
-         col.itemR(md, "use_sharp", text="Sharp Edges")
+         col.label(text="Vertex group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
+         sub = col.column()
+         sub.active = bool(md.vertex_group)
+         sub.prop(md, "protect")
  
-     def EXPLODE(self, layout, ob, md):
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
-         layout.itemR(md, "protect")
+         if wide_ui:
+             col = split.column()
+         col.prop(md, "split_edges")
+         col.prop(md, "unborn")
+         col.prop(md, "alive")
+         col.prop(md, "dead")
  
-         flow = layout.column_flow(2)
-         flow.itemR(md, "split_edges")
-         flow.itemR(md, "unborn")
-         flow.itemR(md, "alive")
-         flow.itemR(md, "dead")
+         layout.operator("object.explode_refresh", text="Refresh")
  
-         layout.itemO("object.explode_refresh", text="Refresh")
+     def FLUID_SIMULATION(self, layout, ob, md, wide_ui):
+         layout.label(text="See Fluid panel.")
  
-     def FLUID_SIMULATION(self, layout, ob, md):
-         layout.itemL(text="See Fluid panel.")
+     def HOOK(self, layout, ob, md, wide_ui):
+         split = layout.split()
  
-     def HOOK(self, layout, ob, md):
-         col = layout.column()
-         col.itemR(md, "object")
+         col = split.column()
+         col.label(text="Object:")
+         col.prop(md, "object", text="")
          if md.object and md.object.type == 'ARMATURE':
-             layout.item_pointerR(md, "subtarget", md.object.data, "bones", text="Bone")
+             col.label(text="Bone:")
+             col.prop_object(md, "subtarget", md.object.data, "bones", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
  
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
+         layout.separator()
  
          split = layout.split()
-         split.itemR(md, "falloff")
-         split.itemR(md, "force", slider=True)
-         layout.itemS()
  
-         row = layout.row()
-         row.itemO("object.hook_reset", text="Reset")
-         row.itemO("object.hook_recenter", text="Recenter")
+         col = split.column()
+         col.prop(md, "falloff")
+         col.prop(md, "force", slider=True)
+         if wide_ui:
+             col = split.column()
+         else:
+             col.separator()
+         col.operator("object.hook_reset", text="Reset")
+         col.operator("object.hook_recenter", text="Recenter")
  
          if ob.mode == 'EDIT':
+             layout.separator()
              row = layout.row()
-             row.itemO("object.hook_select", text="Select")
-             row.itemO("object.hook_assign", text="Assign")
+             row.operator("object.hook_select", text="Select")
+             row.operator("object.hook_assign", text="Assign")
  
-     def LATTICE(self, layout, ob, md):
-         layout.itemR(md, "object")
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
+     def LATTICE(self, layout, ob, md, wide_ui):
+         split = layout.split()
  
-     def MASK(self, layout, ob, md):
-         layout.itemR(md, "mode")
+         col = split.column()
+         col.label(text="Object:")
+         col.prop(md, "object", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
+     def MASK(self, layout, ob, md, wide_ui):
+         split = layout.split()
+         col = split.column()
+         col.label(text="Mode:")
+         col.prop(md, "mode", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
          if md.mode == 'ARMATURE':
-             layout.itemR(md, "armature")
+             col.prop(md, "armature", text="")
          elif md.mode == 'VERTEX_GROUP':
-             layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
-         layout.itemR(md, "inverse")
+             col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
+         sub = col.column()
+         sub.active = bool(md.vertex_group)
+         sub.prop(md, "invert")
+     def MESH_DEFORM(self, layout, ob, md, wide_ui):
+         split = layout.split()
+         col = split.column()
+         col.label(text="Object:")
+         col.prop(md, "object", text="")
+         if md.object and md.object.type == 'ARMATURE':
+             col.label(text="Bone:")
+             col.prop_object(md, "subtarget", md.object.data, "bones", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
  
-     def MESH_DEFORM(self, layout, ob, md):
-         layout.itemR(md, "object")
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
-         layout.itemR(md, "invert")
+         sub = col.column()
+         sub.active = bool(md.vertex_group)
+         sub.prop(md, "invert")
  
-         layout.itemS()
+         layout.separator()
  
          if md.is_bound:
-             layout.itemO("object.meshdeform_bind", text="Unbind")
+             layout.operator("object.meshdeform_bind", text="Unbind")
          else:
-             layout.itemO("object.meshdeform_bind", text="Bind")
-             row = layout.row()
-             row.itemR(md, "precision")
-             row.itemR(md, "dynamic")
+             layout.operator("object.meshdeform_bind", text="Bind")
+             split = layout.split()
  
-     def MIRROR(self, layout, ob, md):
-         layout.itemR(md, "merge_limit")
-         split = layout.split()
+             col = split.column()
+             col.prop(md, "precision")
  
-         col = split.column()
-         col.itemR(md, "x")
-         col.itemR(md, "y")
-         col.itemR(md, "z")
+             if wide_ui:
+                 col = split.column()
+             col.prop(md, "dynamic")
+     def MIRROR(self, layout, ob, md, wide_ui):
+         layout.prop(md, "merge_limit")
+         if wide_ui:
+             split = layout.split(percentage=0.25)
+         else:
+             split = layout.split(percentage=0.4)
  
          col = split.column()
-         col.itemL(text="Textures:")
-         col.itemR(md, "mirror_u")
-         col.itemR(md, "mirror_v")
+         col.label(text="Axis:")
+         col.prop(md, "x")
+         col.prop(md, "y")
+         col.prop(md, "z")
+         if wide_ui:
+             col = split.column()
+         else:
+             subsplit = layout.split()
+             col = subsplit.column()
+         col.label(text="Options:")
+         col.prop(md, "clip", text="Clipping")
+         col.prop(md, "mirror_vertex_groups", text="Vertex Groups")
  
          col = split.column()
-         col.itemR(md, "clip", text="Do Clipping")
-         col.itemR(md, "mirror_vertex_groups", text="Vertex Group")
+         col.label(text="Textures:")
+         col.prop(md, "mirror_u", text="U")
+         col.prop(md, "mirror_v", text="V")
  
-         layout.itemR(md, "mirror_object")
+         col = layout.column()
+         col.label(text="Mirror Object:")
+         col.prop(md, "mirror_object", text="")
  
-     def MULTIRES(self, layout, ob, md):
-         layout.row().itemR(md, "subdivision_type", expand=True)
+     def MULTIRES(self, layout, ob, md, wide_ui):
+         if wide_ui:
+             layout.row().prop(md, "subdivision_type", expand=True)
+         else:
+             layout.row().prop(md, "subdivision_type", text="")
 -        layout.prop(md, "level")
  
          split = layout.split()
 -
          col = split.column()
-         col.itemR(md, "levels", text="Preview")
-         col.itemR(md, "sculpt_levels", text="Sculpt")
-         col.itemR(md, "render_levels", text="Render")
 -        col.operator("object.multires_subdivide", text="Subdivide")
++        col.prop(md, "levels", text="Preview")
++        col.prop(md, "sculpt_levels", text="Sculpt")
++        col.prop(md, "render_levels", text="Render")
  
-         col = split.column()
-         col.itemO("object.multires_subdivide", text="Subdivide")
-         col.itemO("object.multires_higher_levels_delete", text="Delete Higher")
+         if wide_ui:
+             col = split.column()
++
++        col.operator("object.multires_subdivide", text="Subdivide")
+         col.operator("object.multires_higher_levels_delete", text="Delete Higher")
 +        row = col.row()
 +        row.enabled = md.total_levels > 0
-         row.itemR(md, "external")
-     def PARTICLE_INSTANCE(self, layout, ob, md):
-         layout.itemR(md, "object")
-         layout.itemR(md, "particle_system_number")
-         flow = layout.column_flow()
-         flow.itemR(md, "normal")
-         flow.itemR(md, "children")
-         flow.itemR(md, "size")
-         flow.itemR(md, "path")
-         if md.path:
-             flow.itemR(md, "keep_shape")
-         flow.itemR(md, "unborn")
-         flow.itemR(md, "alive")
-         flow.itemR(md, "dead")
-         flow.itemL(md, "")
-         if md.path:
-             flow.itemR(md, "axis", text="")
-         if md.path:
-             row = layout.row()
-             row.itemR(md, "position", slider=True)
-             row.itemR(md, "random_position", text="Random", slider=True)
-     def PARTICLE_SYSTEM(self, layout, ob, md):
-         layout.itemL(text="See Particle panel.")
-     def SHRINKWRAP(self, layout, ob, md):
-         layout.itemR(md, "target")
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
-         layout.itemR(md, "offset")
-         layout.itemR(md, "subsurf_levels")
-         layout.itemR(md, "mode")
++        row.prop(md, "external")
+     def PARTICLE_INSTANCE(self, layout, ob, md, wide_ui):
+         layout.prop(md, "object")
+         layout.prop(md, "particle_system_number", text="Particle System")
+         split = layout.split()
+         col = split.column()
+         col.label(text="Create From:")
+         col.prop(md, "normal")
+         col.prop(md, "children")
+         col.prop(md, "size")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Show Particles When:")
+         col.prop(md, "alive")
+         col.prop(md, "unborn")
+         col.prop(md, "dead")
+         layout.separator()
+         layout.prop(md, "path", text="Create Along Paths")
+         split = layout.split()
+         split.active = md.path
+         col = split.column()
+         col.row().prop(md, "axis", expand=True)
+         col.prop(md, "keep_shape")
+         if wide_ui:
+             col = split.column()
+         col.prop(md, "position", slider=True)
+         col.prop(md, "random_position", text="Random", slider=True)
+     def PARTICLE_SYSTEM(self, layout, ob, md, wide_ui):
+         layout.label(text="See Particle panel.")
+     def SHRINKWRAP(self, layout, ob, md, wide_ui):
+         split = layout.split()
+         col = split.column()
+         col.label(text="Target:")
+         col.prop(md, "target", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
+         split = layout.split()
+         col = split.column()
+         col.prop(md, "offset")
+         col.prop(md, "subsurf_levels")
+         if wide_ui:
+             col = split.column()
+             col.label(text="Mode:")
+         col.prop(md, "mode", text="")
+         if wide_ui:
+             split = layout.split(percentage=0.25)
+         else:
+             split = layout.split(percentage=0.35)
+         col = split.column()
          if md.mode == 'PROJECT':
-             layout.itemR(md, "subsurf_levels")
-             layout.itemR(md, "auxiliary_target")
+             col.label(text="Axis:")
+             col.prop(md, "x")
+             col.prop(md, "y")
+             col.prop(md, "z")
+             col = split.column()
+             col.label(text="Direction:")
+             col.prop(md, "negative")
+             col.prop(md, "positive")
+             if wide_ui:
+                 col = split.column()
+             else:
+                 subsplit = layout.split()
+                 col = subsplit.column()
+             col.label(text="Cull Faces:")
+             col.prop(md, "cull_front_faces", text="Front")
+             col.prop(md, "cull_back_faces", text="Back")
+             layout.label(text="Auxiliary Target:")
+             layout.prop(md, "auxiliary_target", text="")
  
-             row = layout.row()
-             row.itemR(md, "x")
-             row.itemR(md, "y")
-             row.itemR(md, "z")
-             flow = layout.column_flow()
-             flow.itemR(md, "negative")
-             flow.itemR(md, "positive")
-             flow.itemR(md, "cull_front_faces")
-             flow.itemR(md, "cull_back_faces")
          elif md.mode == 'NEAREST_SURFACEPOINT':
-             layout.itemR(md, "keep_above_surface")
-     def SIMPLE_DEFORM(self, layout, ob, md):
-         layout.itemR(md, "mode")
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
-         layout.itemR(md, "origin")
-         layout.itemR(md, "relative")
-         layout.itemR(md, "factor")
-         layout.itemR(md, "limits")
-         if md.mode in ('TAPER', 'STRETCH'):
-             layout.itemR(md, "lock_x_axis")
-             layout.itemR(md, "lock_y_axis")
+             layout.prop(md, "keep_above_surface")
  
-     def SMOKE(self, layout, ob, md):
-         layout.itemL(text="See Smoke panel.")
+     def SIMPLE_DEFORM(self, layout, ob, md, wide_ui):
+         split = layout.split()
+         col = split.column()
+         col.label(text="Mode:")
+         col.prop(md, "mode", text="")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
  
-     def SMOOTH(self, layout, ob, md):
          split = layout.split()
  
          col = split.column()
-         col.itemR(md, "x")
-         col.itemR(md, "y")
-         col.itemR(md, "z")
+         col.label(text="Origin:")
+         col.prop(md, "origin", text="")
+         sub = col.column()
+         sub.active = md.origin
+         sub.prop(md, "relative")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Deform:")
+         col.prop(md, "factor")
+         col.prop(md, "limits", slider=True)
+         if md.mode in ('TAPER', 'STRETCH'):
+             col.prop(md, "lock_x_axis")
+             col.prop(md, "lock_y_axis")
+     def SMOKE(self, layout, ob, md, wide_ui):
+         layout.label(text="See Smoke panel.")
+     def SMOOTH(self, layout, ob, md, wide_ui):
+         split = layout.split(percentage=0.25)
+         col = split.column()
+         col.label(text="Axis:")
+         col.prop(md, "x")
+         col.prop(md, "y")
+         col.prop(md, "z")
  
          col = split.column()
-         col.itemR(md, "factor")
-         col.itemR(md, "repeat")
+         col.prop(md, "factor")
+         col.prop(md, "repeat")
+         col.label(text="Vertex Group:")
+         col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
  
-         layout.item_pointerR(md, "vertex_group", ob, "vertex_groups")
+     def SOFT_BODY(self, layout, ob, md, wide_ui):
+         layout.label(text="See Soft Body panel.")
  
-     def SOFT_BODY(self, layout, ob, md):
-         layout.itemL(text="See Soft Body panel.")
+     def SUBSURF(self, layout, ob, md, wide_ui):
+         if wide_ui:
+             layout.row().prop(md, "subdivision_type", expand=True)
+         else:
+             layout.row().prop(md, "subdivision_type", text="")
  
-     def SUBSURF(self, layout, ob, md):
-         layout.row().itemR(md, "subdivision_type", expand=True)
+         split = layout.split()
+         col = split.column()
+         col.label(text="Subdivisions:")
+         col.prop(md, "levels", text="View")
+         col.prop(md, "render_levels", text="Render")
  
-         flow = layout.column_flow()
-         flow.itemR(md, "levels", text="Preview")
-         flow.itemR(md, "render_levels", text="Render")
-         flow.itemR(md, "optimal_draw", text="Optimal Display")
+         if wide_ui:
+             col = split.column()
+         col.label(text="Options:")
+         col.prop(md, "optimal_draw", text="Optimal Display")
 -        col.prop(md, "subsurf_uv")
  
-     def SURFACE(self, layout, ob, md):
-         layout.itemL(text="See Fields panel.")
+     def SURFACE(self, layout, ob, md, wide_ui):
+         layout.label(text="See Fields panel.")
  
-     def UV_PROJECT(self, layout, ob, md):
+     def UV_PROJECT(self, layout, ob, md, wide_ui):
          if ob.type == 'MESH':
-             layout.item_pointerR(md, "uv_layer", ob.data, "uv_textures")
-             layout.itemR(md, "image")
-             layout.itemR(md, "override_image")
              split = layout.split()
              col = split.column()
-             col.itemL(text="Aspect Ratio:")
+             col.label(text="UV Layer:")
+             col.prop_object(md, "uv_layer", ob.data, "uv_textures", text="")
  
-             sub = col.column(align=True)
-             sub.itemR(md, "horizontal_aspect_ratio", text="Horizontal")
-             sub.itemR(md, "vertical_aspect_ratio", text="Vertical")
+             if wide_ui:
+                 col = split.column()
+             col.label(text="Image:")
+             col.prop(md, "image", text="")
  
+             split = layout.split()
              col = split.column()
-             col.itemL(text="Projectors:")
+             col.prop(md, "override_image")
+             col.prop(md, "num_projectors", text="Projectors")
+             for proj in md.projectors:
+                 col.prop(proj, "object", text="")
  
+             if wide_ui:
+                 col = split.column()
              sub = col.column(align=True)
-             sub.itemR(md, "num_projectors", text="Number")
-             for proj in md.projectors:
-                 sub.itemR(proj, "object", text="")
+             sub.label(text="Aspect Ratio:")
+             sub.prop(md, "horizontal_aspect_ratio", text="Horizontal")
+             sub.prop(md, "vertical_aspect_ratio", text="Vertical")
  
-     def WAVE(self, layout, ob, md):
+     def WAVE(self, layout, ob, md, wide_ui):
          split = layout.split()
  
          col = split.column()
@@@ -161,29 -169,30 +169,31 @@@ class PHYSICS_PT_softbody_edge(PhysicBu
          split = layout.split()
  
          col = split.column()
-         col.itemL(text="Springs:")
-         col.itemR(softbody, "pull")
-         col.itemR(softbody, "push")
-         col.itemR(softbody, "damp")
-         col.itemR(softbody, "plastic")
-         col.itemR(softbody, "bending")
-         col.itemR(softbody, "spring_length", text="Length")
+         col.label(text="Springs:")
+         col.prop(softbody, "pull")
+         col.prop(softbody, "push")
+         col.prop(softbody, "damp")
+         col.prop(softbody, "plastic")
+         col.prop(softbody, "bending")
+         col.prop(softbody, "spring_length", text="Length")
+         col.prop_object(softbody, "spring_vertex_group", ob, "vertex_groups", text="Springs:")
 +        col.item_pointerR(softbody, "spring_vertex_group", ob, "vertex_groups", text="Springs:")
  
-         col = split.column()
-         col.itemR(softbody, "stiff_quads")
+         if wide_ui:
+             col = split.column()
+         col.prop(softbody, "stiff_quads")
          sub = col.column()
          sub.active = softbody.stiff_quads
-         sub.itemR(softbody, "shear")
+         sub.prop(softbody, "shear")
  
-         col.itemR(softbody, "new_aero", text="Aero")
+         col.prop(softbody, "new_aero", text="Aero")
          sub = col.column()
          sub.enabled = softbody.new_aero
-         sub.itemR(softbody, "aero", text="Factor")
+         sub.prop(softbody, "aero", text="Factor")
  
-         col.itemL(text="Collision:")
-         col.itemR(softbody, "edge_collision", text="Edge")
-         col.itemR(softbody, "face_collision", text="Face")
+         col.label(text="Collision:")
+         col.prop(softbody, "edge_collision", text="Edge")
+         col.prop(softbody, "face_collision", text="Face")
  
  
  class PHYSICS_PT_softbody_collision(PhysicButtonsPanel):
@@@ -66,10 -65,10 +65,11 @@@ class CONSOLE_MT_console(bpy.types.Menu
      def draw(self, context):
          layout = self.layout
          layout.column()
-         layout.itemO("console.clear")
-         layout.itemO("console.copy")
-         layout.itemO("console.paste")
+         layout.operator("console.clear")
+         layout.operator("console.copy")
+         layout.operator("console.paste")
+         layout.menu("CONSOLE_MT_language")
 +        layout.itemM("CONSOLE_MT_language")
  
  
  class CONSOLE_MT_report(bpy.types.Menu):
      def draw(self, context):
          layout = self.layout
          layout.column()
-         layout.itemO("console.select_all_toggle")
-         layout.itemO("console.select_border")
-         layout.itemO("console.report_delete")
-         layout.itemO("console.report_copy")
+         layout.operator("console.select_all_toggle")
+         layout.operator("console.select_border")
+         layout.operator("console.report_delete")
+         layout.operator("console.report_copy")
++class CONSOLE_MT_language(bpy.types.Menu):
++    bl_label = "Languages..."
  
  class CONSOLE_MT_language(bpy.types.Menu):
      bl_label = "Languages..."
@@@ -239,25 -231,25 +231,27 @@@ class SEQUENCER_MT_strip(bpy.types.Menu
              stype = strip.type
  
              if        stype == 'EFFECT':
-                 layout.itemS()
-                 layout.itemO("sequencer.effect_change")
-                 layout.itemO("sequencer.effect_reassign_inputs")
+                 layout.separator()
+                 layout.operator("sequencer.effect_change")
+                 layout.operator("sequencer.effect_reassign_inputs")
              elif stype == 'IMAGE':
-                 layout.itemS()
-                 layout.itemO("sequencer.image_change")
+                 layout.separator()
+                 layout.operator("sequencer.image_change")
+                 layout.operator("sequencer.rendersize")
 +                layout.itemO("sequencer.rendersize")
              elif stype == 'SCENE':
-                 layout.itemS()
-                 layout.itemO("sequencer.scene_change", text="Change Scene")
+                 layout.separator()
+                 layout.operator("sequencer.scene_change", text="Change Scene")
              elif stype == 'MOVIE':
-                 layout.itemS()
-                 layout.itemO("sequencer.movie_change")
+                 layout.separator()
+                 layout.operator("sequencer.movie_change")
+                 layout.operator("sequencer.rendersize")
 +                layout.itemO("sequencer.rendersize")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("sequencer.meta_make")
-         layout.itemO("sequencer.meta_separate")
+         layout.operator("sequencer.meta_make")
+         layout.operator("sequencer.meta_separate")
  
          #if (ed && (ed->metastack.first || (ed->act_seq && ed->act_seq->type == SEQ_META))) {
          #     uiItemS(layout);
@@@ -300,23 -369,23 +369,24 @@@ class VIEW3D_MT_select_particle(bpy.typ
      def draw(self, context):
          layout = self.layout
  
-         layout.itemO("view3d.select_border")
+         layout.operator("view3d.select_border")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("particle.select_all_toggle", text="Select/Deselect All")
-         layout.itemO("particle.select_linked")
+         layout.operator("particle.select_all_toggle", text="Select/Deselect All")
+         layout.operator("particle.select_linked")
+         layout.operator("particle.select_inverse")
 +        layout.itemO("particle.select_inverse")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("particle.select_more")
-         layout.itemO("particle.select_less")
+         layout.operator("particle.select_more")
+         layout.operator("particle.select_less")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("particle.select_first", text="Roots")
-         layout.itemO("particle.select_last", text="Tips")
+         layout.operator("particle.select_first", text="Roots")
+         layout.operator("particle.select_last", text="Tips")
  
  
  class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
      def draw(self, context):
          layout = self.layout
  
-         layout.itemO("view3d.select_border")
-         layout.itemO("view3d.select_circle")
+         layout.operator("view3d.select_border")
+         layout.operator("view3d.select_circle")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("mesh.select_all_toggle", text="Select/Deselect All")
-         layout.itemO("mesh.select_inverse", text="Inverse")
+         layout.operator("mesh.select_all_toggle", text="Select/Deselect All")
+         layout.operator("mesh.select_inverse", text="Inverse")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("mesh.select_random", text="Random...")
-         layout.itemO("mesh.edges_select_sharp", text="Sharp Edges")
-         layout.itemO("mesh.faces_select_linked_flat", text="Linked Flat Faces")
+         layout.operator("mesh.select_random", text="Random...")
+         layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
+         layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
+         layout.operator("mesh.faces_select_interior", text="Interior Faces")
+         layout.operator("mesh.select_axis", text="Side of Active")
 +        layout.itemO("mesh.faces_select_interior", text="Interior Faces")
 +        layout.itemO("mesh.select_axis", text="Side of Active")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.item_enumO("mesh.select_by_number_vertices", "type", 'TRIANGLES', text="Triangles")
-         layout.item_enumO("mesh.select_by_number_vertices", "type", 'QUADS', text="Quads")
-         layout.item_enumO("mesh.select_by_number_vertices", "type", 'OTHER', text="Loose Verts/Edges")
-         layout.itemO("mesh.select_similar", text="Similar...")
+         layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES'
+         layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS'
+         layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER'
+         layout.operator("mesh.select_similar", text="Similar...")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("mesh.select_less", text="Less")
-         layout.itemO("mesh.select_more", text="More")
+         layout.operator("mesh.select_less", text="Less")
+         layout.operator("mesh.select_more", text="More")
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("mesh.select_mirror", text="Mirror")
+         layout.operator("mesh.select_mirror", text="Mirror")
  
-         layout.itemO("mesh.select_linked", text="Linked")
-         layout.itemO("mesh.select_vertex_path", text="Vertex Path")
-         layout.itemO("mesh.loop_multi_select", text="Edge Loop")
-         layout.item_booleanO("mesh.loop_multi_select", "ring", True, text="Edge Ring")
+         layout.operator("mesh.select_linked", text="Linked")
+         layout.operator("mesh.select_vertex_path", text="Vertex Path")
+         layout.operator("mesh.loop_multi_select", text="Edge Loop")
+         layout.operator("mesh.loop_multi_select", text="Edge Ring").ring = True
  
-         layout.itemS()
+         layout.separator()
  
-         layout.itemO("mesh.loop_to_region")
-         layout.itemO("mesh.region_to_loop")
+         layout.operator("mesh.loop_to_region")
+         layout.operator("mesh.region_to_loop")
  
  
  class VIEW3D_MT_select_edit_curve(bpy.types.Menu):
@@@ -1359,30 -1513,31 +1516,35 @@@ class VIEW3D_PT_3dview_properties(bpy.t
          scene = context.scene
  
          col = layout.column()
-         col.itemL(text="Camera:")
-         col.itemR(view, "camera", text="")
-         col.itemR(view, "lens")
+         col.label(text="Camera:")
+         col.prop(view, "camera", text="")
+         col.prop(view, "lens")
  
          col = layout.column(align=True)
-         col.itemL(text="Clip:")
-         col.itemR(view, "clip_start", text="Start")
-         col.itemR(view, "clip_end", text="End")
+         col.label(text="Clip:")
+         col.prop(view, "clip_start", text="Start")
+         col.prop(view, "clip_end", text="End")
  
          col = layout.column(align=True)
-         col.itemL(text="Grid:")
-         col.itemR(view, "grid_lines", text="Lines")
-         col.itemR(view, "grid_spacing", text="Spacing")
-         col.itemR(view, "grid_subdivisions", text="Subdivisions")
+         col.label(text="Grid:")
+         col.prop(view, "grid_lines", text="Lines")
+         col.prop(view, "grid_spacing", text="Spacing")
+         col.prop(view, "grid_subdivisions", text="Subdivisions")
  
-         layout.column().itemR(scene, "cursor_location", text="3D Cursor:")
+         layout.column().prop(scene, "cursor_location", text="3D Cursor:")
  
 +class VIEW3D_PT_3dview_item(bpy.types.Panel):
 +    bl_space_type = 'VIEW_3D'
 +    bl_region_type = 'UI'
 +    bl_label = "Item"
  
+ class VIEW3D_PT_3dview_name(bpy.types.Panel):
+     bl_space_type = 'VIEW_3D'
+     bl_region_type = 'UI'
+     bl_label = "Item"
      def poll(self, context):
-         return (context.active_object or context.active_bone or context.active_pchan)
+         return (context.space_data and context.active_object)
  
      def draw(self, context):
          layout = self.layout
@@@ -82,50 -83,63 +83,64 @@@ class VIEW3D_PT_tools_meshedit(View3DPa
          layout = self.layout
  
          col = layout.column(align=True)
-         col.itemL(text="Transform:")
-         col.itemO("tfm.translate")
-         col.itemO("tfm.rotate")
-         col.itemO("tfm.resize", text="Scale")
+         col.label(text="Transform:")
+         col.operator("tfm.translate")
+         col.operator("tfm.rotate")
+         col.operator("tfm.resize", text="Scale")
+         col.operator("tfm.shrink_fatten", text="Along Normal")
  
          col = layout.column(align=True)
-         col.itemL(text="Mesh:")
-         col.itemO("mesh.duplicate_move")
-         col.itemO("mesh.delete")
+         col.label(text="Deform:")
+         col.operator("tfm.edge_slide")
+         col.operator("mesh.rip_move")
+         col.operator("mesh.vertices_smooth")
  
          col = layout.column(align=True)
-         col.itemL(text="Modeling:")
-         col.itemO("mesh.extrude_move")
-         col.itemO("mesh.subdivide")
-         col.itemO("mesh.loopcut")
-         col.itemO("mesh.spin")
-         col.itemO("mesh.screw")
-         col.itemO("mesh.merge")
-         col.itemO("mesh.rip_move")
+         col.label(text="Add:")
+         col.operator("mesh.extrude_move")
+         col.operator("mesh.subdivide")
+         col.operator("mesh.loopcut")
+         col.operator("mesh.duplicate_move")
+         col.operator("mesh.spin")
+         col.operator("mesh.screw")
 +        col.itemO("mesh.flip_normals")
  
          col = layout.column(align=True)
-         col.itemL(text="Shading:")
-         col.itemO("mesh.faces_shade_smooth", text="Smooth")
-         col.itemO("mesh.faces_shade_flat", text="Flat")
+         col.label(text="Remove:")
+         col.operator("mesh.delete")
+         col.operator("mesh.merge")
+         col.operator("mesh.remove_doubles")
+         col = layout.column(align=True)
+         col.label(text="Normals:")
+         col.operator("mesh.normals_make_consistent", text="Recalculate")
+         col.operator("mesh.flip_normals", text="Flip Direction")
  
          col = layout.column(align=True)
-         col.itemL(text="UV Mapping:")
-         col.item_stringO("wm.call_menu", "name", "VIEW3D_MT_uv_map", text="Unwrap")
+         col.label(text="UV Mapping:")
+         col.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map"
+         col.operator("mesh.mark_seam")
+         col.operator("mesh.mark_seam", text="Clear Seam").clear = True
  
-         col.itemO("mesh.uvs_rotate")
-         col.itemO("mesh.uvs_mirror")
+         col = layout.column(align=True)
+         col.label(text="Shading:")
+         col.operator("mesh.faces_shade_smooth", text="Smooth")
+         col.operator("mesh.faces_shade_flat", text="Flat")
  
          col = layout.column(align=True)
-         col.itemL(text="Grease Pencil:")
-         col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand")
-         col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line")
-         col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser")
+         col.label(text="Repeat:")
+         col.operator("screen.repeat_last")
+         col.operator("screen.repeat_history", text="History...")
  
          col = layout.column(align=True)
-         col.itemL(text="Repeat:")
-         col.itemO("screen.repeat_last")
-         col.itemO("screen.repeat_history", text="History...")
-         col.itemO("screen.redo_last", text="Tweak...")
+         col.label(text="Grease Pencil:")
+         row = col.row()
+         row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
+         row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
+         row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
  
  
  class VIEW3D_PT_tools_meshedit_options(View3DPanel):
@@@ -517,19 -551,11 +552,14 @@@ class VIEW3D_PT_tools_brush(PaintPanel)
                  col = layout.column()
  
                  if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'):
-                     col.row().itemR(brush, "direction", expand=True)
+                     col.row().prop(brush, "direction", expand=True)
  
-                     col.itemR(brush, "use_accumulate")
 +                if brush.sculpt_tool in ('DRAW', 'INFLATE', 'LAYER'):
++                    col.prop(brush, "use_accumulate")
 +
                  if brush.sculpt_tool == 'LAYER':
-                     col.itemR(brush, "use_persistent")
-                     col.itemO("sculpt.set_persistent_base")
+                     col.prop(brush, "use_persistent")
+                     col.operator("sculpt.set_persistent_base")
  
          # Texture Paint Mode #
  
@@@ -670,8 -695,8 +699,8 @@@ class VIEW3D_PT_sculpt_options(PaintPan
          sculpt = context.tool_settings.sculpt
  
          col = layout.column()
-         col.itemR(sculpt, "show_brush")
-         col.itemR(sculpt, "fast_navigate")
 -        col.prop(sculpt, "partial_redraw", text="Partial Refresh")
+         col.prop(sculpt, "show_brush")
++        col.prop(sculpt, "fast_navigate")
  
          split = self.layout.split()
  
@@@ -69,8 -68,9 +69,9 @@@ typedef struct SculptSession 
        struct MFace *mface;
        int totvert, totface;
        float *face_normals;
 -
 +      struct PBVH *tree;
        struct Object *ob;
+       struct KeyBlock *kb, *refkb;
        
        /* Mesh connectivity */
        struct ListBase *fmap;
@@@ -1130,643 -1133,6 +1133,643 @@@ CCGError ccgSubSurf_processSync(CCGSubS
        return eCCGError_None;
  }
  
-               if (length>FLT_EPSILON) {
 +#define FACE_getIFNo(f, lvl, S, x, y)         _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
 +#define FACE_calcIFNo(f, lvl, S, x, y, no)    _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
 +static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
 +      CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
 +      int numEffectedV, int numEffectedE, int numEffectedF) {
 +      int i,ptrIdx;
 +      int subdivLevels = ss->subdivLevels;
 +      int lvl = ss->subdivLevels;
 +      int edgeSize = 1 + (1<<lvl);
 +      int gridSize = 1 + (1<<(lvl-1));
 +      int normalDataOffset = ss->normalDataOffset;
 +      int vertDataSize = ss->meshIFC.vertDataSize;
 +
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +              int S, x, y;
 +
 +              for (S=0; S<f->numVerts; S++) {
 +                      for (y=0; y<gridSize-1; y++)
 +                              for (x=0; x<gridSize-1; x++)
 +                                      NormZero(FACE_getIFNo(f, lvl, S, x, y));
 +
 +                      if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected)
 +                              for (x=0; x<gridSize-1; x++)
 +                                      NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1));
 +                      if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
 +                              for (y=0; y<gridSize-1; y++)
 +                                      NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y));
 +                      if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
 +                              NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1));
 +              }
 +      }
 +
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +              int S, x, y;
 +              float no[3];
 +
 +              for (S=0; S<f->numVerts; S++) {
 +                      int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected);
 +                      int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected);
 +                      int yLimitNext = xLimit;
 +                      int xLimitPrev = yLimit;
 +                      
 +                      for (y=0; y<gridSize - 1; y++) {
 +                              for (x=0; x<gridSize - 1; x++) {
 +                                      int xPlusOk = (!xLimit || x<gridSize-2);
 +                                      int yPlusOk = (!yLimit || y<gridSize-2);
 +
 +                                      FACE_calcIFNo(f, lvl, S, x, y, no);
 +
 +                                      NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no);
 +                                      if (xPlusOk)
 +                                              NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no);
 +                                      if (yPlusOk)
 +                                              NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no);
 +                                      if (xPlusOk && yPlusOk) {
 +                                              if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) {
 +                                                      NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no);
 +                                              }
 +                                      }
 +
 +                                      if (x==0 && y==0) {
 +                                              int K;
 +
 +                                              if (!yLimitNext || 1<gridSize-1)
 +                                                      NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no);
 +                                              if (!xLimitPrev || 1<gridSize-1)
 +                                                      NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no);
 +
 +                                              for (K=0; K<f->numVerts; K++) {
 +                                                      if (K!=S) {
 +                                                              NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
 +                                                      }
 +                                              }
 +                                      } else if (y==0) {
 +                                              NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no);
 +                                              if (!yLimitNext || x<gridSize-2)
 +                                                      NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no);
 +                                      } else if (x==0) {
 +                                              NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no);
 +                                              if (!xLimitPrev || y<gridSize-2)
 +                                                      NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +              // XXX can I reduce the number of normalisations here?
 +      for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
 +              CCGVert *v = (CCGVert*) effectedV[ptrIdx];
 +              float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
 +
 +              NormZero(no);
 +
 +              for (i=0; i<v->numFaces; i++) {
 +                      CCGFace *f = v->faces[i];
 +                      NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1));
 +              }
 +
 +              length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
 +
-                                       if (length>FLT_EPSILON) {
++              if (length>EPSILON) {
 +                      float invLength = 1.0f/length;
 +                      no[0] *= invLength;
 +                      no[1] *= invLength;
 +                      no[2] *= invLength;
 +              } else {
 +                      NormZero(no);
 +              }
 +
 +              for (i=0; i<v->numFaces; i++) {
 +                      CCGFace *f = v->faces[i];
 +                      NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no);
 +              }
 +      }
 +      for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
 +              CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
 +
 +              if (e->numFaces) {
 +                      CCGFace *fLast = e->faces[e->numFaces-1];
 +                      int x;
 +
 +                      for (i=0; i<e->numFaces-1; i++) {
 +                              CCGFace *f = e->faces[i];
 +
 +                              for (x=1; x<edgeSize-1; x++) {
 +                                      NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
 +                                                      _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
 +                              }
 +                      }
 +
 +                      for (i=0; i<e->numFaces-1; i++) {
 +                              CCGFace *f = e->faces[i];
 +
 +                              for (x=1; x<edgeSize-1; x++) {
 +                                      NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
 +                                                      _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
 +                              }
 +                      }
 +              }
 +      }
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +              int S;
 +
 +              for (S=0; S<f->numVerts; S++) {
 +                      NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1),
 +                                       FACE_getIFNo(f, lvl, S, gridSize-1, 0));
 +              }
 +      }
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +              int S, x, y;
 +
 +              for (S=0; S<f->numVerts; S++) {
 +                      for (y=0; y<gridSize; y++) {
 +                              for (x=0; x<gridSize; x++) {
 +                                      float *no = FACE_getIFNo(f, lvl, S, x, y);
 +                                      float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
 +
++                                      if (length>EPSILON) {
 +                                              float invLength = 1.0f/length;
 +                                              no[0] *= invLength;
 +                                              no[1] *= invLength;
 +                                              no[2] *= invLength;
 +                                      } else {
 +                                              NormZero(no);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +#undef FACE_getIFNo
 +
 +#define VERT_getCo(v, lvl)                            _vert_getCo(v, lvl, vertDataSize)
 +#define EDGE_getCo(e, lvl, x)                 _edge_getCo(e, lvl, x, vertDataSize)
 +#define FACE_getIECo(f, lvl, S, x)            _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
 +#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
 +static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
 +      CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
 +      int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) {
 +      int subdivLevels = ss->subdivLevels;
 +      int edgeSize = 1 + (1<<curLvl);
 +      int gridSize = 1 + (1<<(curLvl-1));
 +      int nextLvl = curLvl+1;
 +      int ptrIdx, S, y, x, i, cornerIdx;
 +      void *q = ss->q, *r = ss->r;
 +      int vertDataSize = ss->meshIFC.vertDataSize;
 +
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +
 +                      /* interior face midpoints
 +                       *  o old interior face points
 +                       */
 +              for (S=0; S<f->numVerts; S++) {
 +                      for (y=0; y<gridSize-1; y++) {
 +                              for (x=0; x<gridSize-1; x++) {
 +                                      int fx = 1 + 2*x;
 +                                      int fy = 1 + 2*y;
 +                                      void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
 +                                      void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
 +                                      void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
 +                                      void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
 +                                      void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
 +
 +                                      VertDataAvg4(co, co0, co1, co2, co3);
 +                              }
 +                      }
 +              }
 +
 +                      /* interior edge midpoints
 +                       *  o old interior edge points
 +                       *  o new interior face midpoints
 +                       */
 +              for (S=0; S<f->numVerts; S++) {
 +                      for (x=0; x<gridSize-1; x++) {
 +                              int fx = x*2 + 1;
 +                              void *co0 = FACE_getIECo(f, curLvl, S, x+0);
 +                              void *co1 = FACE_getIECo(f, curLvl, S, x+1);
 +                              void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
 +                              void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
 +                              void *co = FACE_getIECo(f, nextLvl, S, fx);
 +                              
 +                              VertDataAvg4(co, co0, co1, co2, co3);
 +                      }
 +
 +                                      /* interior face interior edge midpoints
 +                                       *  o old interior face points
 +                                       *  o new interior face midpoints
 +                                       */
 +
 +                              /* vertical */
 +                      for (x=1; x<gridSize-1; x++) {
 +                              for (y=0; y<gridSize-1; y++) {
 +                                      int fx = x*2;
 +                                      int fy = y*2+1;
 +                                      void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
 +                                      void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
 +                                      void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
 +                                      void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
 +                                      void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
 +
 +                                      VertDataAvg4(co, co0, co1, co2, co3);
 +                              }
 +                      }
 +
 +                              /* horizontal */
 +                      for (y=1; y<gridSize-1; y++) {
 +                              for (x=0; x<gridSize-1; x++) {
 +                                      int fx = x*2+1;
 +                                      int fy = y*2;
 +                                      void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
 +                                      void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
 +                                      void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
 +                                      void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
 +                                      void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
 +
 +                                      VertDataAvg4(co, co0, co1, co2, co3);
 +                              }
 +                      }
 +              }
 +      }
 +
 +              /* exterior edge midpoints
 +               *  o old exterior edge points
 +               *  o new interior face midpoints
 +               */
 +      for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
 +              CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
 +              float sharpness = EDGE_getSharpness(e, curLvl);
 +
 +              if (_edge_isBoundary(e) || sharpness>1.0) {
 +                      for (x=0; x<edgeSize-1; x++) {
 +                              int fx = x*2 + 1;
 +                              void *co0 = EDGE_getCo(e, curLvl, x+0);
 +                              void *co1 = EDGE_getCo(e, curLvl, x+1);
 +                              void *co = EDGE_getCo(e, nextLvl, fx);
 +
 +                              VertDataCopy(co, co0);
 +                              VertDataAdd(co, co1);
 +                              VertDataMulN(co, 0.5);
 +                      }
 +              } else {
 +                      for (x=0; x<edgeSize-1; x++) {
 +                              int fx = x*2 + 1;
 +                              void *co0 = EDGE_getCo(e, curLvl, x+0);
 +                              void *co1 = EDGE_getCo(e, curLvl, x+1);
 +                              void *co = EDGE_getCo(e, nextLvl, fx);
 +                              int numFaces = 0;
 +
 +                              VertDataCopy(q, co0);
 +                              VertDataAdd(q, co1);
 +
 +                              for (i=0; i<e->numFaces; i++) {
 +                                      CCGFace *f = e->faces[i];
 +                                      VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
 +                                      numFaces++;
 +                              }
 +
 +                              VertDataMulN(q, 1.0f/(2.0f+numFaces));
 +
 +                              VertDataCopy(r, co0);
 +                              VertDataAdd(r, co1);
 +                              VertDataMulN(r, 0.5);
 +
 +                              VertDataCopy(co, q);
 +                              VertDataSub(r, q);
 +                              VertDataMulN(r, sharpness);
 +                              VertDataAdd(co, r);
 +                      }
 +              }
 +      }
 +
 +              /* exterior vertex shift
 +               *  o old vertex points (shifting)
 +               *  o old exterior edge points
 +               *  o new interior face midpoints
 +               */
 +      for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
 +              CCGVert *v = (CCGVert*) effectedV[ptrIdx];
 +              void *co = VERT_getCo(v, curLvl);
 +              void *nCo = VERT_getCo(v, nextLvl);
 +              int sharpCount = 0, allSharp = 1;
 +              float avgSharpness = 0.0;
 +              int seam = VERT_seam(v), seamEdges = 0;
 +
 +              for (i=0; i<v->numEdges; i++) {
 +                      CCGEdge *e = v->edges[i];
 +                      float sharpness = EDGE_getSharpness(e, curLvl);
 +
 +                      if (seam && _edge_isBoundary(e))
 +                              seamEdges++;
 +
 +                      if (sharpness!=0.0f) {
 +                              sharpCount++;
 +                              avgSharpness += sharpness;
 +                      } else {
 +                              allSharp = 0;
 +                      }
 +              }
 +
 +              if(sharpCount) {
 +                      avgSharpness /= sharpCount;
 +                      if (avgSharpness>1.0) {
 +                              avgSharpness = 1.0;
 +                      }
 +              }
 +
 +              if (seam && seamEdges < 2)
 +                      seam = 0;
 +
 +              if (!v->numEdges) {
 +                      VertDataCopy(nCo, co);
 +              } else if (_vert_isBoundary(v)) {
 +                      int numBoundary = 0;
 +
 +                      VertDataZero(r);
 +                      for (i=0; i<v->numEdges; i++) {
 +                              CCGEdge *e = v->edges[i];
 +                              if (_edge_isBoundary(e)) {
 +                                      VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
 +                                      numBoundary++;
 +                              }
 +                      }
 +
 +                      VertDataCopy(nCo, co);
 +                      VertDataMulN(nCo, 0.75);
 +                      VertDataMulN(r, 0.25f/numBoundary);
 +                      VertDataAdd(nCo, r);
 +              } else {
 +                      int cornerIdx = (1 + (1<<(curLvl))) - 2;
 +                      int numEdges = 0, numFaces = 0;
 +
 +                      VertDataZero(q);
 +                      for (i=0; i<v->numFaces; i++) {
 +                              CCGFace *f = v->faces[i];
 +                              VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
 +                              numFaces++;
 +                      }
 +                      VertDataMulN(q, 1.0f/numFaces);
 +                      VertDataZero(r);
 +                      for (i=0; i<v->numEdges; i++) {
 +                              CCGEdge *e = v->edges[i];
 +                              VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
 +                              numEdges++;
 +                      }
 +                      VertDataMulN(r, 1.0f/numEdges);
 +
 +                      VertDataCopy(nCo, co);
 +                      VertDataMulN(nCo, numEdges-2.0f);
 +                      VertDataAdd(nCo, q);
 +                      VertDataAdd(nCo, r);
 +                      VertDataMulN(nCo, 1.0f/numEdges);
 +              }
 +
 +              if ((sharpCount>1 && v->numFaces) || seam) {
 +                      VertDataZero(q);
 +
 +                      if (seam) {
 +                              avgSharpness = 1.0f;
 +                              sharpCount = seamEdges;
 +                              allSharp = 1;
 +                      }
 +
 +                      for (i=0; i<v->numEdges; i++) {
 +                              CCGEdge *e = v->edges[i];
 +                              float sharpness = EDGE_getSharpness(e, curLvl);
 +
 +                              if (seam) {
 +                                      if (_edge_isBoundary(e))
 +                                              VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
 +                              } else if (sharpness != 0.0) {
 +                                      VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
 +                              }
 +                      }
 +
 +                      VertDataMulN(q, (float) 1/sharpCount);
 +
 +                      if (sharpCount!=2 || allSharp) {
 +                                      // q = q + (co-q)*avgSharpness
 +                              VertDataCopy(r, co);
 +                              VertDataSub(r, q);
 +                              VertDataMulN(r, avgSharpness);
 +                              VertDataAdd(q, r);
 +                      }
 +
 +                              // r = co*.75 + q*.25
 +                      VertDataCopy(r, co);
 +                      VertDataMulN(r, .75);
 +                      VertDataMulN(q, .25);
 +                      VertDataAdd(r, q);
 +
 +                              // nCo = nCo  + (r-nCo)*avgSharpness
 +                      VertDataSub(r, nCo);
 +                      VertDataMulN(r, avgSharpness);
 +                      VertDataAdd(nCo, r);
 +              }
 +      }
 +
 +              /* exterior edge interior shift
 +               *  o old exterior edge midpoints (shifting)
 +               *  o old exterior edge midpoints
 +               *  o new interior face midpoints
 +               */
 +      for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
 +              CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
 +              float sharpness = EDGE_getSharpness(e, curLvl);
 +              int sharpCount = 0;
 +              float avgSharpness = 0.0;
 +
 +              if (sharpness!=0.0f) {
 +                      sharpCount = 2;
 +                      avgSharpness += sharpness;
 +
 +                      if (avgSharpness>1.0) {
 +                              avgSharpness = 1.0;
 +                      }
 +              } else {
 +                      sharpCount = 0;
 +                      avgSharpness = 0;
 +              }
 +
 +              if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
 +                      for (x=1; x<edgeSize-1; x++) {
 +                              int fx = x*2;
 +                              void *co = EDGE_getCo(e, curLvl, x);
 +                              void *nCo = EDGE_getCo(e, nextLvl, fx);
 +                              VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
 +                              VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
 +                              VertDataMulN(r, 0.5);
 +                              VertDataCopy(nCo, co);
 +                              VertDataMulN(nCo, 0.75);
 +                              VertDataMulN(r, 0.25);
 +                              VertDataAdd(nCo, r);
 +                      }
 +              } else {
 +                      for (x=1; x<edgeSize-1; x++) {
 +                              int fx = x*2;
 +                              void *co = EDGE_getCo(e, curLvl, x);
 +                              void *nCo = EDGE_getCo(e, nextLvl, fx);
 +                              int numFaces = 0;
 +
 +                              VertDataZero(q);
 +                              VertDataZero(r);
 +                              VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
 +                              VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
 +                              for (i=0; i<e->numFaces; i++) {
 +                                      CCGFace *f = e->faces[i];
 +                                      VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
 +                                      VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
 +
 +                                      VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
 +                                      numFaces++;
 +                              }
 +                              VertDataMulN(q, 1.0/(numFaces*2.0f));
 +                              VertDataMulN(r, 1.0/(2.0f + numFaces));
 +
 +                              VertDataCopy(nCo, co);
 +                              VertDataMulN(nCo, (float) numFaces);
 +                              VertDataAdd(nCo, q);
 +                              VertDataAdd(nCo, r);
 +                              VertDataMulN(nCo, 1.0f/(2+numFaces));
 +
 +                              if (sharpCount==2) {
 +                                      VertDataCopy(q, co);
 +                                      VertDataMulN(q, 6.0f);
 +                                      VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
 +                                      VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
 +                                      VertDataMulN(q, 1/8.0f);
 +
 +                                      VertDataSub(q, nCo);
 +                                      VertDataMulN(q, avgSharpness);
 +                                      VertDataAdd(nCo, q);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
 +              CCGFace *f = (CCGFace*) effectedF[ptrIdx];
 +
 +                      /* interior center point shift
 +                       *  o old face center point (shifting)
 +                       *  o old interior edge points
 +                       *  o new interior face midpoints
 +                       */
 +              VertDataZero(q);
 +              for (S=0; S<f->numVerts; S++) {
 +                      VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
 +              }
 +              VertDataMulN(q, 1.0f/f->numVerts);
 +              VertDataZero(r);
 +              for (S=0; S<f->numVerts; S++) {
 +                      VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
 +              }
 +              VertDataMulN(r, 1.0f/f->numVerts);
 +
 +              VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
 +              VertDataAdd(FACE_getCenterData(f), q);
 +              VertDataAdd(FACE_getCenterData(f), r);
 +              VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
 +
 +              for (S=0; S<f->numVerts; S++) {
 +                              /* interior face shift
 +                               *  o old interior face point (shifting)
 +                               *  o new interior edge midpoints
 +                               *  o new interior face midpoints
 +                               */
 +                      for (x=1; x<gridSize-1; x++) {
 +                              for (y=1; y<gridSize-1; y++) {
 +                                      int fx = x*2;
 +                                      int fy = y*2;
 +                                      void *co = FACE_getIFCo(f, curLvl, S, x, y);
 +                                      void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
 +                                      
 +                                      VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
 +                                              FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
 +                                              FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
 +                                              FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
 +
 +                                      VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
 +                                              FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
 +                                              FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
 +                                              FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
 +
 +                                      VertDataCopy(nCo, co);
 +                                      VertDataSub(nCo, q);
 +                                      VertDataMulN(nCo, 0.25f);
 +                                      VertDataAdd(nCo, r);
 +                              }
 +                      }
 +
 +                              /* interior edge interior shift
 +                               *  o old interior edge point (shifting)
 +                               *  o new interior edge midpoints
 +                               *  o new interior face midpoints
 +                               */
 +                      for (x=1; x<gridSize-1; x++) {
 +                              int fx = x*2;
 +                              void *co = FACE_getIECo(f, curLvl, S, x);
 +                              void *nCo = FACE_getIECo(f, nextLvl, S, fx);
 +                              
 +                              VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
 +                                      FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
 +                                      FACE_getIFCo(f, nextLvl, S, fx+1, +1),
 +                                      FACE_getIFCo(f, nextLvl, S, fx-1, +1));
 +
 +                              VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
 +                                      FACE_getIECo(f, nextLvl, S, fx+1),
 +                                      FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
 +                                      FACE_getIFCo(f, nextLvl, S, fx, 1));
 +
 +                              VertDataCopy(nCo, co);
 +                              VertDataSub(nCo, q);
 +                              VertDataMulN(nCo, 0.25f);
 +                              VertDataAdd(nCo, r);
 +                      }
 +              }
 +      }
 +
 +              /* copy down */
 +      edgeSize = 1 + (1<<(nextLvl));
 +      gridSize = 1 + (1<<((nextLvl)-1));
 +      cornerIdx = gridSize-1;
 +      for (i=0; i<numEffectedE; i++) {
 +              CCGEdge *e = effectedE[i];
 +              VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
 +              VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
 +      }
 +      for (i=0; i<numEffectedF; i++) {
 +              CCGFace *f = effectedF[i];
 +              for (S=0; S<f->numVerts; S++) {
 +                      CCGEdge *e = FACE_getEdges(f)[S];
 +                      CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
 +
 +                      VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
 +                      VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
 +                      VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
 +                      VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
 +                      for (x=1; x<gridSize-1; x++) {
 +                              void *co = FACE_getIECo(f, nextLvl, S, x);
 +                              VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
 +                              VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
 +                      }
 +                      for (x=0; x<gridSize-1; x++) {
 +                              int eI = gridSize-1-x;
 +                              VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
 +                              VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
 +                      }
 +              }
 +      }
 +}
 +
 +
  static void ccgSubSurf__sync(CCGSubSurf *ss) {
        CCGVert **effectedV;
        CCGEdge **effectedE;
@@@ -123,13 -118,13 +123,14 @@@ static void paint_draw_cursor(bContext 
  static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
  {
        PointerRNA itemptr;
 -      float cur_depth, pressure = 1;
 -      float center[3];
 +      float pressure = 1;
 +      float center[3] = {0, 0, 0};
+       int flip= event->shift?1:0;
        PaintStroke *stroke = op->customdata;
  
 -      cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]);
 -      view3d_unproject(&stroke->mats, center, mouse[0], mouse[1], cur_depth); 
 +      /* XXX: can remove the if statement once all modes have this */
 +      if(stroke->get_location)
 +              stroke->get_location(C, stroke, center, mouse);
  
        /* Tablet */
        if(event->custom == EVT_DATA_TABLET) {
@@@ -134,7 -142,7 +136,8 @@@ typedef struct StrokeCache 
        float flip;
        float pressure;
        float mouse[2];
 +      float bstrength;
+       float tex_mouse[2];
  
        /* The rest is temporary storage that isn't saved as a property */
  
@@@ -549,169 -239,6 +552,169 @@@ static float brush_strength(Sculpt *sd
        }
  }
  
-                       float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize;
-                       float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize;
 +/* Uses symm to selectively flip any axis of a coordinate. */
 +static void flip_coord(float out[3], float in[3], const char symm)
 +{
 +      if(symm & SCULPT_SYMM_X)
 +              out[0]= -in[0];
 +      else
 +              out[0]= in[0];
 +      if(symm & SCULPT_SYMM_Y)
 +              out[1]= -in[1];
 +      else
 +              out[1]= in[1];
 +      if(symm & SCULPT_SYMM_Z)
 +              out[2]= -in[2];
 +      else
 +              out[2]= in[2];
 +}
 +
 +/* Get a pixel from the texcache at (px, py) */
 +static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
 +{
 +      unsigned *p;
 +      p = ss->texcache + py * ss->texcache_side + px;
 +      return ((unsigned char*)(p))[0];
 +}
 +
 +static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
 +{
 +      int x, y, x2, y2;
 +      const int tc_max = ss->texcache_side - 1;
 +      float urat, vrat, uopp;
 +
 +      if(u < 0) u = 0;
 +      else if(u >= ss->texcache_side) u = tc_max;
 +      if(v < 0) v = 0;
 +      else if(v >= ss->texcache_side) v = tc_max;
 +
 +      x = floor(u);
 +      y = floor(v);
 +      x2 = x + 1;
 +      y2 = y + 1;
 +
 +      if(x2 > ss->texcache_side) x2 = tc_max;
 +      if(y2 > ss->texcache_side) y2 = tc_max;
 +      
 +      urat = u - x;
 +      vrat = v - y;
 +      uopp = 1 - urat;
 +              
 +      return ((get_texcache_pixel(ss, x, y) * uopp +
 +               get_texcache_pixel(ss, x2, y) * urat) * (1 - vrat) + 
 +              (get_texcache_pixel(ss, x, y2) * uopp +
 +               get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
 +}
 +
 +/* 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 = NULL;
 +      float avg= 1;
 +
 +      if(br->texact >= 0)
 +              tex = br->mtex[br->texact];
 +
 +      if(!tex) {
 +              avg= 1;
 +      }
 +      else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
 +              float jnk;
 +
 +              /* Get strength by feeding the vertex 
 +                 location directly into a texture */
 +              externtex(tex, 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];
 +
 +              /* 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);
 +
 +              /* 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);
 +              }
 +              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);
 +              }
 +      }
 +
 +      avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
 +
 +      return avg;
 +}
 +
 +typedef struct {
 +      Sculpt *sd;
 +      SculptSession *ss;
 +      float radius_squared;
 +      ListBase *active_verts;
 +      float area_normal[3];
 +} SculptSearchSphereData;
 +
 +/* Test AABB against sphere */
 +static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
 +{
 +      SculptSearchSphereData *data = data_v;
 +      float *center = data->ss->cache->location, nearest[3];
 +      float t[3], bb_min[3], bb_max[3];
 +      int i;
 +
 +      BLI_pbvh_node_get_BB(node, bb_min, bb_max);
 +
 +      for(i = 0; i < 3; ++i) {
 +              if(bb_min[i] > center[i])
 +                      nearest[i] = bb_min[i];
 +              else if(bb_max[i] < center[i])
 +                      nearest[i] = bb_max[i];
 +              else
 +                      nearest[i] = center[i]; 
 +      }
 +      
 +      sub_v3_v3v3(t, center, nearest);
 +
 +      return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
 +}
 +
  /* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
  static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float val[3])
  {
@@@ -1237,86 -833,77 +1240,80 @@@ static void do_flatten_clay_brush(Sculp
  
  static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
  {
 +      SculptSearchSphereData data;
        Brush *brush = paint_brush(&sd->paint);
 -      float av_dist;
 -      ListBase active_verts={0,0};
 -      ListBase *grab_active_verts = &ss->cache->grab_active_verts[ss->cache->symmetry];
 -      ActiveData *adata= 0;
 -      float *vert;
 -      const float bstrength= brush_strength(sd, cache);
 -      Brush *b = brush;
 -      int i;
 +      //KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
 +      PBVHNode **nodes= NULL;
 +      int totnode;
  
 -      sculpt_add_damaged_rect(ss);
 -
 -      /* Build a list of all vertices that are potentially within the brush's
 -         area of influence. Only do this once for the grab brush. */
 -      if((b->sculpt_tool != SCULPT_TOOL_GRAB) || cache->first_time) {
 -              for(i=0; i<ss->totvert; ++i) {
 -                      /* Projverts.inside provides a rough bounding box */
 -                      if(ss->multires || ss->projverts[i].inside) {
 -                              //vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : a->verts[i].co;
 -                              vert= ss->mvert[i].co;
 -                              av_dist= len_v3v3(ss->cache->location, vert);
 -                              if(av_dist < cache->radius) {
 -                                      adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
 -
 -                                      adata->Index = i;
 -                                      /* Fade is used to store the final strength at which the brush
 -                                         should modify a particular vertex. */
 -                                      adata->Fade= tex_strength(sd, ss, vert, av_dist) * bstrength;
 -                                      adata->dist = av_dist;
 -
 -                                      if(b->sculpt_tool == SCULPT_TOOL_GRAB && cache->first_time)
 -                                              BLI_addtail(grab_active_verts, adata);
 -                                      else
 -                                              BLI_addtail(&active_verts, adata);
 -                              }
 -                      }
 +      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) {
 +              if(cache->first_time) {
 +                      /* For the grab tool we store these nodes once in the beginning
 +                         and then reuse them. */
 +                      BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
 +                              &nodes, &totnode);
 +                      
 +                      ss->cache->grab_active_nodes[ss->cache->symmetry]= nodes;
 +                      ss->cache->grab_active_totnode[ss->cache->symmetry]= totnode;
 +                      copy_v3_v3(ss->cache->grab_active_location[ss->cache->symmetry], ss->cache->location);
 +              }
 +              else {
 +                      nodes= ss->cache->grab_active_nodes[ss->cache->symmetry];
 +                      totnode= ss->cache->grab_active_totnode[ss->cache->symmetry];
 +                      copy_v3_v3(ss->cache->location, ss->cache->grab_active_location[ss->cache->symmetry]);
                }
        }
 +      else {
 +              BLI_pbvh_search_gather(ss->tree, sculpt_search_sphere_cb, &data,
 +                      &nodes, &totnode);
 +      }
  
        /* Only act if some verts are inside the brush area */
 -      if(active_verts.first || (b->sculpt_tool == SCULPT_TOOL_GRAB && grab_active_verts->first)) {
 +      if(totnode) {
                /* Apply one type of brush action */
 -              switch(b->sculpt_tool){
 +              switch(brush->sculpt_tool){
                case SCULPT_TOOL_DRAW:
 -                      do_draw_brush(sd, ss, &active_verts);
 +                      do_draw_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_SMOOTH:
 -                      do_smooth_brush(sd, ss, &active_verts);
 +                      do_smooth_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_PINCH:
 -                      do_pinch_brush(sd, ss, &active_verts);
 +                      do_pinch_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_INFLATE:
 -                      do_inflate_brush(sd, ss, &active_verts);
 +                      do_inflate_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_GRAB:
 -                      do_grab_brush(sd, ss);
 +                      do_grab_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_LAYER:
 -                      do_layer_brush(sd, ss, &active_verts);
 +                      do_layer_brush(sd, ss, nodes, totnode);
                        break;
                case SCULPT_TOOL_FLATTEN:
 -                      do_flatten_clay_brush(sd, ss, &active_verts, 0);
 +                      do_flatten_clay_brush(sd, ss, nodes, totnode, 0);
                        break;
                case SCULPT_TOOL_CLAY:
 -                      do_flatten_clay_brush(sd, ss, &active_verts, 1);
 +                      do_flatten_clay_brush(sd, ss, nodes, totnode, 1);
 +                      break;
                }
        
 +#if 0
                /* Copy the modified vertices from mesh to the active key */
-               if(keyblock && !ss->multires) {
-                       float *co= keyblock->data;
-                       if(co) {
-                               if(b->sculpt_tool == SCULPT_TOOL_GRAB)
-                                       adata = grab_active_verts->first;
-                               else
-                                       adata = active_verts.first;
+               if(ss->kb) mesh_to_key(ss->ob->data, ss->kb);
  
 +                              for(; adata; adata= adata->next)
 +                                      if(adata->Index < keyblock->totelem)
 +                                              copy_v3_v3(&co[adata->Index*3], me->mvert[adata->Index].co);
 +                      }
 +              }
 +
                if(ss->vertexcosnos && !ss->multires)
                        BLI_freelistN(&active_verts);
                else {
@@@ -1416,13 -1116,17 +1413,15 @@@ struct MultiresModifierData *sculpt_mul
        return NULL;
  }
  
 -static void sculpt_update_mesh_elements(bContext *C)
 +void sculpt_update_mesh_elements(bContext *C, int need_fmap)
  {
        Object *ob = CTX_data_active_object(C);
 +      DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, 0);
        SculptSession *ss = ob->sculpt;
 -      int oldtotvert = ss->totvert;
 -      DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
 -
 +      
+       ss->ob= ob;
        if((ss->multires = sculpt_multires_active(ob))) {
 -              //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
                ss->totvert = dm->getNumVerts(dm);
                ss->totface = dm->getNumFaces(dm);
                ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
                ss->mface = me->mface;
                ss->face_normals = NULL;
        }
 -      if( GPU_buffer_legacy( dm ) ) {
 -              ss->drawobject = 0;
 -      }
 -      else {
 -              ss->drawobject = dm->drawObject;
 -      }
  
 -      if(ss->totvert != oldtotvert) {
 -              if(ss->projverts) MEM_freeN(ss->projverts);
 -              ss->projverts = NULL;
 -
 -              if(ss->fmap) MEM_freeN(ss->fmap);
 -              if(ss->fmap_mem) MEM_freeN(ss->fmap_mem);
 -              create_vert_face_map(&ss->fmap, &ss->fmap_mem, ss->mface, ss->totvert, ss->totface);
 -              ss->fmap_size = ss->totvert;
 -      }
 +      ss->ob = ob;
 +      ss->tree = dm->getPBVH(ob, dm);
 +      ss->fmap = (need_fmap)? dm->getFaceMap(dm): NULL;
+       if((ob->shapeflag & OB_SHAPE_LOCK) && !sculpt_multires_active(ob)) {
+               ss->kb= ob_get_keyblock(ob);
+               ss->refkb= ob_get_reference_keyblock(ob);
+       }
+       else {
+               ss->kb= NULL;
+               ss->refkb= NULL;
+       }
  }
  
  static int sculpt_mode_poll(bContext *C)
@@@ -1563,9 -1290,10 +1571,9 @@@ static void sculpt_update_cache_invaria
        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);
 -      cache->depth = RNA_float_get(op->ptr, "depth");
  
-       cache->mouse[0] = cache->initial_mouse[0];
-       cache->mouse[1] = cache->initial_mouse[1];
+       copy_v2_v2(cache->mouse, cache->initial_mouse);
+       copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
  
        /* Truly temporary data that isn't stored in properties */
  
@@@ -1772,14 -1444,24 +1783,20 @@@ static void sculpt_brush_stroke_init_pr
        mouse[0] = event->x;
        mouse[1] = event->y;
        RNA_float_set_array(op->ptr, "initial_mouse", mouse);
 -
 -      /* Initial screen depth under the mouse */
 -      RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y));
 -
 -      sculpt_update_cache_invariants(sd, ss, C, op);
  }
  
- static void sculpt_brush_stroke_init(bContext *C)
+ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
  {
+       Object *ob= CTX_data_active_object(C);
        Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        SculptSession *ss = CTX_data_active_object(C)->sculpt;
 +      Brush *brush = paint_brush(&sd->paint);
  
+       if(ob_get_key(ob) && !(ob->shapeflag & OB_SHAPE_LOCK)) {
+               BKE_report(reports, RPT_ERROR, "Shape key sculpting requires a locked shape.");
+               return 0;
+       }
        view3d_operator_needs_opengl(C);
  
        /* TODO: Shouldn't really have to do this at the start of every
           changes are made to the texture. */
        sculpt_update_tex(sd, ss);
  
 -      sculpt_update_mesh_elements(C);
 +      sculpt_update_mesh_elements(C, brush->sculpt_tool == SCULPT_TOOL_SMOOTH);
+       if(ss->kb) key_to_mesh(ss->kb, ss->ob->data);
+       return 1;
  }
  
  static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
@@@ -1914,10 -1601,10 +1936,11 @@@ static void sculpt_stroke_done(bContex
  
  static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
  {
-       sculpt_brush_stroke_init(C);
+       if(!sculpt_brush_stroke_init(C, op->reports))
+               return OPERATOR_CANCELLED;
  
 -      op->customdata = paint_stroke_new(C, sculpt_stroke_test_start,
 +      op->customdata = paint_stroke_new(C, sculpt_stroke_get_location,
 +                                        sculpt_stroke_test_start,
                                          sculpt_stroke_update_step,
                                          sculpt_stroke_done);
  
@@@ -1934,12 -1621,13 +1957,13 @@@ static int sculpt_brush_stroke_exec(bCo
        Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        SculptSession *ss = CTX_data_active_object(C)->sculpt;
  
 -      op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done);
+       if(!sculpt_brush_stroke_init(C, op->reports))
+               return OPERATOR_CANCELLED;
 +      op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
 +                                        sculpt_stroke_update_step, sculpt_stroke_done);
  
-       sculpt_brush_stroke_init(C);
        sculpt_update_cache_invariants(sd, ss, C, op);
 -      sculptmode_update_all_projverts(ss);
  
        paint_stroke_exec(C, op);
  
@@@ -2027,14 -1713,11 +2051,15 @@@ static int sculpt_toggle_mode(bContext 
  {
        ToolSettings *ts = CTX_data_tool_settings(C);
        Object *ob = CTX_data_active_object(C);
 +      MultiresModifierData *mmd = sculpt_multires_active(ob);
  
        if(ob->mode & OB_MODE_SCULPT) {
-               multires_force_update(ob);
+               if(sculpt_multires_active(ob))
+                       multires_force_update(ob);
  
 +              if(mmd && mmd->sculptlvl != mmd->lvl)
 +                      DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
 +
                /* Leave sculptmode */
                ob->mode &= ~OB_MODE_SCULPT;
  
@@@ -482,46 -483,9 +486,47 @@@ void VIEW3D_OT_setobjectascamera(wmOper
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
  }
  /* ********************************** */
  
 +void view3d_calculate_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
 +{
 +      double xs, ys, p[3];
 +      short val;
 +
 +      /* near zero floating point values can give issues with gluUnProject
 +              in side view on some implementations */
 +      if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
 +      if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
 +
 +      /* Set up viewport so that gluUnProject will give correct values */
 +      mats->viewport[0] = 0;
 +      mats->viewport[1] = 0;
 +
 +      /* four clipping planes and bounding volume */
 +      /* first do the bounding volume */
 +      for(val=0; val<4; val++) {
 +              xs= (val==0||val==3)?rect->xmin:rect->xmax;
 +              ys= (val==0||val==1)?rect->ymin:rect->ymax;
 +
 +              gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
 +              VECCOPY(bb->vec[val], p);
 +
 +              gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
 +              VECCOPY(bb->vec[4+val], p);
 +      }
 +
 +      /* then plane equations */
 +      for(val=0; val<4; val++) {
 +
 +              normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
 +
 +              planes[val][3]= - planes[val][0]*bb->vec[val][0]
 +                      - planes[val][1]*bb->vec[val][1]
 +                      - planes[val][2]*bb->vec[val][2];
 +      }
 +}
 +
  /* create intersection coordinates in view Z direction at mouse coordinates */
  void viewline(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_end[3])
  {
@@@ -574,7 -577,72 +577,71 @@@ static void rna_Object_dimensions_set(P
        }
  }
  
+ static int rna_Object_location_editable(PointerRNA *ptr, int index)
+ {
+       Object *ob= (Object *)ptr->data;
+       
+       /* only if the axis in question is locked, not editable... */
+       if ((index == 0) && (ob->protectflag & OB_LOCK_LOCX))
+               return 0;
+       else if ((index == 1) && (ob->protectflag & OB_LOCK_LOCY))
+               return 0;
+       else if ((index == 2) && (ob->protectflag & OB_LOCK_LOCZ))
+               return 0;
+       else
+               return PROP_EDITABLE;
+ }
+ static int rna_Object_scale_editable(PointerRNA *ptr, int index)
+ {
+       Object *ob= (Object *)ptr->data;
+       
+       /* only if the axis in question is locked, not editable... */
+       if ((index == 0) && (ob->protectflag & OB_LOCK_SCALEX))
+               return 0;
+       else if ((index == 1) && (ob->protectflag & OB_LOCK_SCALEY))
+               return 0;
+       else if ((index == 2) && (ob->protectflag & OB_LOCK_SCALEZ))
+               return 0;
+       else
+               return PROP_EDITABLE;
+ }
+ static int rna_Object_rotation_euler_editable(PointerRNA *ptr, int index)
+ {
+       Object *ob= (Object *)ptr->data;
+       
+       /* only if the axis in question is locked, not editable... */
+       if ((index == 0) && (ob->protectflag & OB_LOCK_ROTX))
+               return 0;
+       else if ((index == 1) && (ob->protectflag & OB_LOCK_ROTY))
+               return 0;
+       else if ((index == 2) && (ob->protectflag & OB_LOCK_ROTZ))
+               return 0;
+       else
+               return PROP_EDITABLE;
+ }
+ static int rna_Object_rotation_4d_editable(PointerRNA *ptr, int index)
+ {
+       Object *ob= (Object *)ptr->data;
+       
+       /* only consider locks if locking components individually... */
+       if (ob->protectflag & OB_LOCK_ROT4D) {
+               /* only if the axis in question is locked, not editable... */
+               if ((index == 0) && (ob->protectflag & OB_LOCK_ROTW))
+                       return 0;
+               else if ((index == 1) && (ob->protectflag & OB_LOCK_ROTX))
+                       return 0;
+               else if ((index == 2) && (ob->protectflag & OB_LOCK_ROTY))
+                       return 0;
+               else if ((index == 3) && (ob->protectflag & OB_LOCK_ROTZ))
+                       return 0;
+       }
+               
+       return PROP_EDITABLE;
+ }
  
 -
  static PointerRNA rna_MaterialSlot_material_get(PointerRNA *ptr)
  {
        Object *ob= (Object*)ptr->id.data;
@@@ -170,14 -187,7 +187,15 @@@ static void rna_def_paint(BlenderRNA *b
        RNA_def_property_pointer_funcs(prop, "rna_Paint_active_brush_get", "rna_Paint_active_brush_set", NULL);
        RNA_def_property_flag(prop, PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "Brush", "Active paint brush.");
+       RNA_def_property_update(prop, NC_BRUSH|NA_EDITED, NULL);
 +
 +      prop= RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH);
 +      RNA_def_property_ui_text(prop, "Show Brush", "");
 +
 +      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.");
  }
  
  static void rna_def_sculpt(BlenderRNA  *brna)