Sculpt: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r24257...
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 4 Nov 2009 21:21:30 +0000 (21:21 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 4 Nov 2009 21:21:30 +0000 (21:21 +0000)
45 files changed:
intern/guardedalloc/intern/mallocn.c
release/scripts/ui/space_view3d.py
release/scripts/ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/cdderivedmesh.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/blenkernel/intern/particle.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenlib/BLI_pbvh.h [new file with mode: 0644]
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/SConscript
source/blender/blenlib/intern/arithb.c
source/blender/blenlib/intern/pbvh.c [new file with mode: 0644]
source/blender/editors/include/ED_sculpt.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/object/object_modifier.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/paint_undo.c [new file with mode: 0644]
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_intern.h
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/editors/util/ed_util.c
source/blender/editors/util/undo.c
source/blender/gpu/gpu_buffers.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/render/intern/source/convertblender.c

index ca7f2a4d5067bc97a443b411f93e106c0c76e73a..6845e8922b36ed8a56128a9e2be2e79fbc60452b 100644 (file)
@@ -407,6 +407,38 @@ void MEM_printmemlist_stats()
        printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use/(double)(1024*1024));
        for(a=0, pb=printblock; a<totpb; a++, pb++)
                printf("%s items: %d, len: %.3f MB\n", pb->name, pb->items, (double)pb->len/(double)(1024*1024));
+       
+       {
+               uintptr_t other= mem_in_use;
+
+               printf(
+                       "from pylab import *\n"
+                       "\n"
+                       "figure(1, figsize=(10,10))\n"
+                       "\n"
+                       "memory = [\n");
+
+               for(a=0, pb=printblock; a<totpb; a++, pb++) {
+                       printf("[\"%s\", %.3f],\n", pb->name, (double)pb->len/(double)(1024*1024));
+                       other -= pb->len;
+
+                       if((double)pb->len/(double)mem_in_use < 0.025)
+                               break;
+               }
+
+               printf(
+                       "[\"other\", %.3f]]\n"
+                       "\n"
+                       "labels = [m[0] for m in memory]\n"
+                       "fracs = [m[1] for m in memory]\n"
+                       "map = cm.get_cmap(\"Paired\")\n"
+                       "colors = [map(float(i)/len(fracs)) for i in range(0, len(fracs))]\n"
+                       "\n"
+                       "pie(fracs, labels=labels, colors=colors, autopct='%%1.1f%%%%')\n"
+                       "title(\"Memory Usage: %.3f MB\")\n"
+                       "\n"
+                       "show()\n", (double)other/(double)(1024*1024), (double)mem_in_use/(double)(1024*1024));
+       }
 
        free(printblock);
        
index 1567da12173310dc3d96a4e2b4ef0a342f2e1a56..5d64f9e4779e8610fa940b47465109ac0756a98e 100644 (file)
@@ -663,7 +663,8 @@ class VIEW3D_MT_sculpt(bpy.types.Menu):
                 layout.itemR(brush, "use_anchor")
 
             if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'):
-                layout.itemR(brush, "flip_direction")
+                layout.item_enumR(brush, "direction", value="SUBTRACT")
+                layout.item_enumR(brush, "direction", value="ADD")
 
             if brush.sculpt_tool == 'LAYER':
                 layout.itemR(brush, "use_persistent")
index 12a9417e3194c1c76208348659e8873301eac5c9..0ad694efde11e5704620354361e42fae40a2dbed 100644 (file)
@@ -666,7 +666,6 @@ class VIEW3D_PT_sculpt_options(PaintPanel):
         sculpt = context.tool_settings.sculpt
 
         col = layout.column()
-        col.itemR(sculpt, "partial_redraw", text="Partial Refresh")
         col.itemR(sculpt, "show_brush")
 
         split = self.layout.split()
index 076747cb8454cf498b1e9fd2f3945ffeb39a2c95..d9b0c4bc357972526e79463fbcd1bba3e0f1e3ab 100644 (file)
@@ -59,6 +59,8 @@ struct MCol;
 struct ColorBand;
 struct GPUVertexAttribs;
 struct GPUDrawObject;
+struct ListBase;
+struct PBVH;
 
 /* number of sub-elements each mesh element has (for interpolation) */
 #define SUB_ELEMS_VERT 0
@@ -73,6 +75,7 @@ struct DerivedMesh {
        int needsFree; /* checked on ->release, is set to 0 for cached results */
        int deformedOnly; /* set by modifier stack if only deformed from original */
        BVHCache bvhCache;
+
        struct GPUDrawObject *drawObject;
 
        /* Misc. Queries */
@@ -180,6 +183,14 @@ struct DerivedMesh {
        /* Get vertex normal, undefined if index is not valid */
        void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
 
+       /* Get a map of vertices to faces
+        */
+       struct ListBase *(*getFaceMap)(DerivedMesh *dm);
+
+       /* Get the BVH used for paint modes
+        */
+       struct PBVH *(*getPBVH)(DerivedMesh *dm);
+
        /* Drawing Operations */
 
        /* Draw all vertices as bgl points (no options) */
@@ -204,7 +215,7 @@ struct DerivedMesh {
         *
         * Also called for *final* editmode DerivedMeshes
         */
-       void (*drawFacesSolid)(DerivedMesh *dm,
+       void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
                               int (*setMaterial)(int, void *attribs));
 
        /* Draw all faces
index 09c1ab9f7d6865b3768fe2667e38bed930a72efb..edb4e2cf2a900617b699ed22bcee10df0efb5a84 100644 (file)
@@ -47,6 +47,7 @@ struct Object;
 struct MTFace;
 struct VecNor;
 struct CustomData;
+struct Scene;
 
 #ifdef __cplusplus
 extern "C" {
index ba42aca18724864098a46c798672f0bf78518ee3..2b4fb9d938d2747d1cefa3b638b345bfa714979e 100644 (file)
@@ -34,6 +34,7 @@ struct MultireModifierData;
 struct MVert;
 struct Object;
 struct Paint;
+struct PBVH;
 struct Scene;
 struct StrokeCache;
 
@@ -68,22 +69,23 @@ typedef struct SculptSession {
        struct MFace *mface;
        int totvert, totface;
        float *face_normals;
+       struct PBVH *tree;
+       struct Object *ob;
        
        /* Mesh connectivity */
        struct ListBase *fmap;
-       struct IndexNode *fmap_mem;
-       int fmap_size;
 
        /* Used temporarily per-stroke */
        float *vertexcosnos;
-       ListBase damaged_rects;
-       ListBase damaged_verts;
+
+       /* Partial redraw */
+       int partial_redraw;
        
        /* Used to cache the render of the active texture */
        unsigned int texcache_side, *texcache, texcache_actual;
 
        /* Layer brush persistence between strokes */
-       float (*mesh_co_orig)[3]; /* Copy of the mesh vertices' locations */
+       float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
        float *layer_disps; /* Displacements for each vertex */
 
        struct SculptStroke *stroke;
index 115d31b587c64f47f155f6bc792ec2bc6e698d39..8a4ffca82449bc6898aa672303058e128771e237 100644 (file)
@@ -83,7 +83,7 @@ Brush *add_brush(const char *name)
        brush->clone.alpha= 0.5;
        brush->sculpt_tool = SCULPT_TOOL_DRAW;
 
-       brush_curve_preset(brush, BRUSH_PRESET_SHARP);
+       brush_curve_preset(brush, BRUSH_PRESET_SMOOTH);
 
        /* enable fake user by default */
        brush->id.flag |= LIB_FAKEUSER;
index e38bb00fe8d937014ffbf55f7839531b1c3098cc..7cc46d3915891d5e39ebe2aadbe6d8e414587cff 100644 (file)
@@ -49,7 +49,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_edgehash.h"
 #include "BLI_editVert.h"
-#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
 
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
@@ -77,6 +77,12 @@ typedef struct {
        MVert *mvert;
        MEdge *medge;
        MFace *mface;
+
+       /* Cached */
+       struct PBVH *pbvh;
+       /* Mesh connectivity */
+       struct ListBase *fmap;
+       struct IndexNode *fmap_mem;
 } CDDerivedMesh;
 
 /**************** DerivedMesh interface functions ****************/
@@ -171,6 +177,33 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
        no_r[2] = no[2]/32767.f;
 }
 
+static ListBase *cdDM_getFaceMap(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+       if(!cddm->fmap) {
+               create_vert_face_map(&cddm->fmap, &cddm->fmap_mem, cddm->mface,
+                                    dm->getNumVerts(dm), dm->getNumFaces(dm));
+               printf("rebuild fmap\n");
+       }
+
+       return cddm->fmap;
+}
+
+static struct PBVH *cdDM_getPBVH(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+       if(!cddm->pbvh) {
+               cddm->pbvh = BLI_pbvh_new();
+               BLI_pbvh_build(cddm->pbvh, cddm->mface, cddm->mvert,
+                              dm->getNumFaces(dm), dm->getNumVerts(dm));
+               printf("rebuild pbvh\n");
+       }
+
+       return cddm->pbvh;
+}
+
 static void cdDM_drawVerts(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -360,7 +393,61 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
        }
 }
 
-static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
+static int nodes_drawn = 0;
+static int is_partial = 0;
+/* XXX: Just a temporary replacement for the real drawing code */
+static void draw_partial_cb(PBVHNode *node, void *data)
+{
+       /* XXX: Just some quick code to show leaf nodes in different colors */
+       /*float col[3]; int i;
+       if(is_partial) {
+               col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
+       }
+       else {
+               srand((long long)data_v);
+               for(i = 0; i < 3; ++i)
+                       col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
+       }
+       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
+
+       glColor3f(1, 0, 0);*/
+       GPU_draw_buffers(BLI_pbvh_node_get_draw_buffers(node));
+       ++nodes_drawn;
+}
+
+/* Adapted from:
+   http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
+   Returns true if the AABB is at least partially within the frustum
+   (ok, not a real frustum), false otherwise.
+*/
+int planes_contain_AABB(PBVHNode *node, float bb_min[3], float bb_max[3], void *data)
+{
+       float (*planes)[4] = data;
+       int i, axis;
+       float vmin[3], vmax[3];
+
+       for(i = 0; i < 4; ++i) { 
+               for(axis = 0; axis < 3; ++axis) {
+                       if(planes[i][axis] > 0) { 
+                               vmin[axis] = bb_min[axis];
+                               vmax[axis] = bb_max[axis];
+                       }
+                       else {
+                               vmin[axis] = bb_max[axis];
+                               vmax[axis] = bb_min[axis];
+                       }
+               }
+               
+               if(Inpf(planes[i], vmin) + planes[i][3] > 0)
+                       return 0;
+       } 
+
+       return 1;
+}
+
+static void cdDM_drawFacesSolid(DerivedMesh *dm,
+                               float (*partial_redraw_planes)[4],
+                               int (*setMaterial)(int, void *attribs))
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
@@ -376,6 +463,35 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a
        glVertex3fv(mvert[index].co);   \
 }
 
+       if(cddm->pbvh) {
+               float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+               BLI_pbvh_update(cddm->pbvh, PBVH_UpdateNormals|PBVH_UpdateDrawBuffers,
+                       face_nors);
+
+               /* should be per face */
+               if(dm->numFaceData && mface->flag & ME_SMOOTH)
+                       glShadeModel(GL_SMOOTH);
+
+               if(partial_redraw_planes) {
+                       BLI_pbvh_search_callback(cddm->pbvh, planes_contain_AABB,
+                                       partial_redraw_planes, draw_partial_cb, NULL);
+               }
+               else {
+                       BLI_pbvh_search_callback(cddm->pbvh, NULL, NULL,
+                                       draw_partial_cb, NULL);
+               }
+
+               is_partial = !!partial_redraw_planes;
+
+               //printf("nodes drawn=%d\n", nodes_drawn);
+               nodes_drawn = 0;
+
+               glShadeModel(GL_FLAT);
+
+               return;
+       }
+
        if( GPU_buffer_legacy(dm) ) {
                DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
                glBegin(glmode = GL_QUADS);
@@ -895,7 +1011,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                continue;
                        }
                        else if(setDrawOptions) {
-                               orig = index[a];
+                               orig = (index)? index[a]: a;
 
                                if(orig == ORIGINDEX_NONE)
                                        continue;
@@ -1289,12 +1405,21 @@ static void cdDM_foreachMappedFaceCenter(
        }
 }
 
+static void cdDM_free_internal(CDDerivedMesh *cddm)
+{
+       if(cddm->pbvh) BLI_pbvh_free(cddm->pbvh);
+       if(cddm->fmap) MEM_freeN(cddm->fmap);
+       if(cddm->fmap_mem) MEM_freeN(cddm->fmap_mem);
+}
+
 static void cdDM_release(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 
-       if (DM_release(dm))
+       if (DM_release(dm)) {
+               cdDM_free_internal(cddm);
                MEM_freeN(cddm);
+       }
 }
 
 /**************** CDDM interface functions ****************/
@@ -1329,6 +1454,9 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->getVertCo = cdDM_getVertCo;
        dm->getVertNo = cdDM_getVertNo;
 
+       dm->getPBVH = cdDM_getPBVH;
+       dm->getFaceMap = cdDM_getFaceMap;
+
        dm->drawVerts = cdDM_drawVerts;
 
        dm->drawUVEdges = cdDM_drawUVEdges;
@@ -1380,17 +1508,12 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
        DerivedMesh *dm = &cddm->dm;
        CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
-       int i, *index, alloctype;
+       int alloctype;
 
-       /* this does a referenced copy, the only new layers being ORIGINDEX,
-        * with an exception for fluidsim */
+       /* this does a referenced copy, with an exception for fluidsim */
 
        DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
 
-       CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
-       CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
-       CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
-
        dm->deformedOnly = 1;
 
        alloctype= CD_REFERENCE;
@@ -1406,18 +1529,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 
-       index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totvert; ++i, ++index)
-               *index = i;
-
-       index = CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totedge; ++i, ++index)
-               *index = i;
-
-       index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totface; ++i, ++index)
-               *index = i;
-
        return dm;
 }
 
@@ -1562,6 +1673,13 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
 
+       if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+       if(!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+       if(!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
@@ -1814,6 +1932,7 @@ static void MultiresDM_release(DerivedMesh *dm)
        }
 
        if(DM_release(dm)) {
+               cdDM_free_internal(&mrdm->cddm);
                MEM_freeN(mrdm->subco);
                MEM_freeN(mrdm->orco);
                if(mrdm->vert_face_map)
@@ -1865,6 +1984,13 @@ DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts
        else
                DM_init(dm, numVerts, numEdges, numFaces);
 
+       if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+       if(!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+       if(!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
index a319838a56f916683ad445190687aaf7e880819b..a94fd8f6bd28165f5a3f17207c30eb4ed31c3787 100644 (file)
@@ -440,15 +440,14 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, char *substring, f
        /* only continue if there's a valid DerivedMesh */
        if (dm) {
                MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
-               int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
                int numVerts = dm->getNumVerts(dm);
                int i, j, count = 0;
                float co[3], nor[3];
                
-               /* check that dvert and index are valid pointers (just in case) */
-               if (dvert && index) {
+               /* check that dvert is a valid pointers (just in case) */
+               if (dvert) {
                        /* get the average of all verts with that are in the vertex-group */
-                       for (i = 0; i < numVerts; i++, index++) {       
+                       for (i = 0; i < numVerts; i++) {        
                                for (j = 0; j < dvert[i].totweight; j++) {
                                        /* does this vertex belong to nominated vertex group? */
                                        if (dvert[i].dw[j].def_nr == dgroup) {
index 3c52dc0af84a63ff792b81f65562b569f41a137f..1193e8247bed014484ce2b1d657e8924517472b1 100644 (file)
@@ -5696,7 +5696,7 @@ static void hookModifier_deformVerts(
                                /* if DerivedMesh is present and has original index data,
                                * use it
                                */
-                               if(dm && dm->getVertData(dm, 0, CD_ORIGINDEX)) {
+                               if(dm && dm->getVertDataArray(dm, CD_ORIGINDEX)) {
                                        int j;
                                        int orig_index;
                                        for(j = 0; j < numVerts; ++j) {
index ba8d41f54bb1705fcbd6d0caf78b9a907fd1b52e..6f0749e0fcd7a40e74c4494fac981106ebbdd39a 100644 (file)
@@ -228,14 +228,6 @@ void free_sculptsession(SculptSession **ssp)
 {
        if(ssp && *ssp) {
                SculptSession *ss = *ssp;
-               if(ss->projverts)
-                       MEM_freeN(ss->projverts);
-
-               if(ss->fmap)
-                       MEM_freeN(ss->fmap);
-
-               if(ss->fmap_mem)
-                       MEM_freeN(ss->fmap_mem);
 
                if(ss->texcache)
                        MEM_freeN(ss->texcache);
@@ -243,8 +235,8 @@ void free_sculptsession(SculptSession **ssp)
                if(ss->layer_disps)
                        MEM_freeN(ss->layer_disps);
 
-               if(ss->mesh_co_orig)
-                       MEM_freeN(ss->mesh_co_orig);
+               if(ss->layer_co)
+                       MEM_freeN(ss->layer_co);
 
                MEM_freeN(ss);
 
@@ -1786,13 +1778,15 @@ static void give_parvert(Object *par, int nr, float *vec)
                        DerivedMesh *dm = par->derivedFinal;
                        
                        if(dm) {
-                               int i, count = 0, numVerts = dm->getNumVerts(dm);
+                               int i, count = 0, vindex, numVerts = dm->getNumVerts(dm);
                                int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
                                float co[3];
 
                                /* get the average of all verts with (original index == nr) */
-                               for(i = 0; i < numVerts; ++i, ++index) {
-                                       if(*index == nr) {
+                               for(i = 0; i < numVerts; ++i) {
+                                       vindex= (index)? *index: i;
+
+                                       if(vindex == nr) {
                                                dm->getVertCo(dm, i, co);
                                                VecAddf(vec, vec, co);
                                                count++;
index 3dfe3966e2fe1ef2ac0c3f3068e3888cebd5f3da..5cc2190c08879b43f9048884385792dc76e3f1e4 100644 (file)
@@ -175,6 +175,8 @@ void paint_init(Paint *p, const char col[3])
 
        memcpy(p->paint_cursor_col, col, 3);
        p->paint_cursor_col[3] = 128;
+
+       p->flags |= PAINT_SHOW_BRUSH;
 }
 
 void free_paint(Paint *paint)
index 43a624b30138760e6ea0903c75bd0b2152ae0fd3..6bd2a03a628d4a395cc1e1338a356244c4876d20 100644 (file)
@@ -790,7 +790,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
        totface= dm->getNumFaces(dm);
        totorigface= me->totface;
 
-       if(totface == 0 || totorigface == 0 || origindex == NULL)
+       if(totface == 0 || totorigface == 0)
                return tot;
 
        facearea= MEM_callocN(sizeof(float)*totorigface, "SimplifyFaceArea");
@@ -807,14 +807,14 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
 
        /* compute number of children per original face */
        for(a=0; a<tot; a++) {
-               b= origindex[ctx->index[a]];
+               b= (origindex)? origindex[ctx->index[a]]: ctx->index[a];
                if(b != -1)
                        elems[b].totchild++;
        }
 
        /* compute areas and centers of original faces */
        for(mf=mface, a=0; a<totface; a++, mf++) {
-               b= origindex[a];
+               b= (origindex)? origindex[a]: a;
 
                if(b != -1) {
                        VECCOPY(co1, mvert[mf->v1].co);
@@ -910,7 +910,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
 
        skipped= 0;
        for(a=0, newtot=0; a<tot; a++) {
-               b= origindex[ctx->index[a]];
+               b= (origindex)? origindex[ctx->index[a]]: ctx->index[a];
                if(b != -1) {
                        if(elems[b].curchild++ < ceil(elems[b].lambda*elems[b].totchild)) {
                                ctx->index[newtot]= ctx->index[a];
@@ -943,7 +943,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float
        if(!data->dosimplify)
                return 0;
        
-       b= data->origindex[cpa->num];
+       b= (data->origindex)? data->origindex[cpa->num]: cpa->num;
        if(b == -1)
                return 0;
 
index 6e95fe7ebc7b19a356226c2243ace6da471b5d39..125c8a0c464b173fb042d1aa4a2c03f802ce213f 100644 (file)
@@ -546,7 +546,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
        // load verts
        faceBase = i = 0;
        mvert = CDDM_get_verts(result);
-       origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
+       origIndex = result->getVertDataArray(result, CD_ORIGINDEX);
 
        for(index = 0; index < totface; index++) {
                CCGFace *f = faceMap2[index];
@@ -663,7 +663,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
        // load edges
        i = 0;
        med = CDDM_get_edges(result);
-       origIndex = result->getEdgeData(result, 0, CD_ORIGINDEX);
+       origIndex = result->getEdgeDataArray(result, CD_ORIGINDEX);
 
        for(index = 0; index < totface; index++) {
                CCGFace *f = faceMap2[index];
@@ -738,7 +738,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
        // load faces
        i = 0;
        mf = CDDM_get_faces(result);
-       origIndex = result->getFaceData(result, 0, CD_ORIGINDEX);
+       origIndex = result->getFaceDataArray(result, CD_ORIGINDEX);
 
        for(index = 0; index < totface; index++) {
                CCGFace *f = faceMap2[index];
@@ -846,7 +846,7 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
 
        mv = mvert;
        index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
-       for(i = 0; i < totvert; i++, mv++, index++) {
+       for(i = 0; i < totvert; i++, mv++) {
                CCGVert *v;
 
                if(vertexCos) {
@@ -855,12 +855,12 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                        ccgSubSurf_syncVert(ss, SET_INT_IN_POINTER(i), mv->co, 0, &v);
                }
 
-               ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = *index;
+               ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = (index)? *index++: i;
        }
 
        me = medge;
        index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
-       for(i = 0; i < totedge; i++, me++, index++) {
+       for(i = 0; i < totedge; i++, me++) {
                CCGEdge *e;
                float crease;
 
@@ -870,12 +870,12 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                ccgSubSurf_syncEdge(ss, SET_INT_IN_POINTER(i), SET_INT_IN_POINTER(me->v1),
                                    SET_INT_IN_POINTER(me->v2), crease, &e);
 
-               ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index;
+               ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index)? *index++: i;
        }
 
        mf = mface;
        index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
-       for (i = 0; i < totface; i++, mf++, index++) {
+       for (i = 0; i < totface; i++, mf++) {
                CCGFace *f;
 
                fVerts[0] = SET_INT_IN_POINTER(mf->v1);
@@ -901,7 +901,7 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                        return;
                }
 
-               ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = *index;
+               ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = (index)? *index++: i;
        }
 
        ccgSubSurf_processSync(ss);
@@ -1615,7 +1615,7 @@ static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
 }
 
        /* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
+static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], int (*setMaterial)(int, void *attribs)) {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
        CCGSubSurf *ss = ccgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
new file mode 100644 (file)
index 0000000..ba9de46
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * A BVH for high poly meshes.
+ * 
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_PBVH_H
+#define BLI_PBVH_H
+
+struct MFace;
+struct MVert;
+struct PBVH;
+struct PBVHNode;
+struct ListBase;
+
+typedef struct PBVH PBVH;
+typedef struct PBVHNode PBVHNode;
+
+/* Callbacks */
+
+/* returns 1 if the search should continue from this node, 0 otherwise */
+typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node,
+       float bb_min[3], float bb_max[3], void *data);
+
+typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
+
+/* Building */
+
+PBVH *BLI_pbvh_new(void);
+void BLI_pbvh_build(PBVH *bvh, struct MFace *faces, struct MVert *verts,
+                   int totface, int totvert);
+void BLI_pbvh_free(PBVH *bvh);
+
+void BLI_pbvh_set_source(PBVH *bvh, struct MVert *, struct MFace *mface);
+
+/* Hierarchical Search in the BVH, two methods:
+   * for each hit calling a callback
+   * gather nodes in an array (easy to multithread) */
+
+void BLI_pbvh_search_callback(PBVH *bvh,
+       BLI_pbvh_SearchCallback scb, void *search_data,
+       BLI_pbvh_HitCallback hcb, void *hit_data);
+
+void BLI_pbvh_search_gather(PBVH *bvh,
+       BLI_pbvh_SearchCallback scb, void *search_data,
+       PBVHNode ***array, int *tot);
+
+/* Raycast
+   the hit callback is called for all leaf nodes intersecting the ray;
+   it's up to the callback to find the primitive within the leaves that is
+   hit first */
+
+void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+                     float ray_start[3], float ray_normal[3]);
+
+/* Node Access */
+
+typedef enum {
+       PBVH_Leaf = 1,
+
+       PBVH_UpdateNormals = 2,
+       PBVH_UpdateBB = 4,
+       PBVH_UpdateDrawBuffers = 8,
+       PBVH_UpdateRedraw = 16
+} PBVHNodeFlags;
+
+void BLI_pbvh_node_mark_update(PBVHNode *node);
+
+void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert);
+void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int *totface);
+void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node);
+
+/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
+
+void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
+void BLI_pbvh_redraw_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3]);
+
+#endif /* BLI_PBVH_H */
+
index 4ed9eb4b007d8725aead5991864f2db6345a3bc2..00a5440bc751d3a0902ce2ca702180da329ccb39 100644 (file)
@@ -28,6 +28,7 @@ FILE(GLOB SRC intern/*.c)
 
 SET(INC 
        . ../makesdna ../blenkernel ../../../intern/guardedalloc ../include
+       ../gpu
        ${FREETYPE_INCLUDE_DIRS}
        ${ZLIB_INC}
 )
index fc586de508513b247ee99d8c0b868444f36e1ee9..bca9399bc2783792943b7f30170a5dcecec6f326 100644 (file)
@@ -4,7 +4,7 @@ Import ('env')
 sources = env.Glob('intern/*.c')
 
 cflags=''
-incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../editors/include'
+incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../editors/include ../gpu'
 incs += ' ' + env['BF_FREETYPE_INC']
 incs += ' ' + env['BF_ZLIB_INC']
 defs = ''
index 874756135e59ac3279f68f5f9a3dfd577ffb63ff..4b54de25101d5997157ff0913abe7635ed1ae74d 100644 (file)
@@ -114,16 +114,17 @@ float sasqrtf(float fac)
 
 float Normalize(float *n)
 {
-       float d;
+       float d, invd;
        
        d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
        /* A larger value causes normalize errors in a scaled down models with camera xtreme close */
        if(d>1.0e-35f) {
                d= (float)sqrt(d);
+               invd= 1.0f/d;
 
-               n[0]/=d; 
-               n[1]/=d; 
-               n[2]/=d;
+               n[0]*=invd; 
+               n[1]*=invd; 
+               n[2]*=invd;
        } else {
                n[0]=n[1]=n[2]= 0.0f;
                d= 0.0f;
@@ -4504,7 +4505,7 @@ int RayIntersectsTriangle(float p1[3], float d[3], float v0[3], float v1[3], flo
        
        Crossf(p, d, e2);
        a = Inpf(e1, p);
-       if ((a > -0.000001) && (a < 0.000001)) return 0;
+       if ((a > -FLT_EPSILON) && (a < FLT_EPSILON)) return 0;
        f = 1.0f/a;
        
        VecSubf(s, p1, v0);
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
new file mode 100644 (file)
index 0000000..2a1f148
--- /dev/null
@@ -0,0 +1,935 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <float.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
+
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "gpu_buffers.h"
+
+#define LEAF_LIMIT 10000
+
+//#define PERFCNTRS
+
+/* Bitmap */
+typedef char* BLI_bitmap;
+
+BLI_bitmap BLI_bitmap_new(int tot)
+{
+       return MEM_callocN((tot >> 3) + 1, "BLI bitmap");
+}
+
+int BLI_bitmap_get(BLI_bitmap b, int index)
+{
+       return b[index >> 3] & (1 << (index & 7));
+}
+
+void BLI_bitmap_set(BLI_bitmap b, int index)
+{
+       b[index >> 3] |= (1 << (index & 7));
+}
+
+void BLI_bitmap_clear(BLI_bitmap b, int index)
+{
+       b[index >> 3] &= ~(1 << (index & 7));
+}
+
+/* Axis-aligned bounding box */
+typedef struct {
+       float bmin[3], bmax[3];
+} BB;
+
+/* Axis-aligned bounding box with centroid */
+typedef struct {
+       float bmin[3], bmax[3], bcentroid[3];
+} BBC;
+
+struct PBVHNode {
+       /* Opaque handle for drawing code */
+       void *draw_buffers;
+
+       int *vert_indices;
+
+       /* Voxel bounds */
+       BB vb;
+
+       /* For internal nodes */
+       int children_offset;
+
+       /* Pointer into bvh face_indices */
+       int *face_indices;
+
+       unsigned short totface;
+       unsigned short uniq_verts, face_verts;
+
+       char flag;
+};
+
+struct PBVH {
+       PBVHNode *nodes;
+       int node_mem_count, totnode;
+
+       int *face_indices;
+       int totface;
+       int totvert;
+
+       /* Mesh data */
+       MVert *verts;
+       MFace *faces;
+
+       /* Only used during BVH build and update,
+          don't need to remain valid after */
+       BLI_bitmap vert_bitmap;
+
+#ifdef PERFCNTRS
+       int perf_modified;
+#endif
+};
+
+#define STACK_FIXED_DEPTH      100
+
+typedef struct PBVHStack {
+       PBVHNode *node;
+       int revisiting;
+} PBVHStack;
+
+typedef struct PBVHIter {
+       PBVH *bvh;
+       BLI_pbvh_SearchCallback scb;
+       void *search_data;
+
+       PBVHStack *stack;
+       int stacksize;
+
+       PBVHStack stackfixed[STACK_FIXED_DEPTH];
+       int stackspace;
+} PBVHIter;
+
+static void BB_reset(BB *bb)
+{
+       bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
+       bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
+}
+
+/* Expand the bounding box to include a new coordinate */
+static void BB_expand(BB *bb, float co[3])
+{
+       int i;
+       for(i = 0; i < 3; ++i) {
+               bb->bmin[i] = MIN2(bb->bmin[i], co[i]);
+               bb->bmax[i] = MAX2(bb->bmax[i], co[i]);
+       }
+}
+
+/* Expand the bounding box to include another bounding box */
+static void BB_expand_with_bb(BB *bb, BB *bb2)
+{
+       int i;
+       for(i = 0; i < 3; ++i) {
+               bb->bmin[i] = MIN2(bb->bmin[i], bb2->bmin[i]);
+               bb->bmax[i] = MAX2(bb->bmax[i], bb2->bmax[i]);
+       }
+}
+
+/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
+static int BB_widest_axis(BB *bb)
+{
+       float dim[3];
+       int i;
+
+       for(i = 0; i < 3; ++i)
+               dim[i] = bb->bmax[i] - bb->bmin[i];
+
+       if(dim[0] > dim[1]) {
+               if(dim[0] > dim[2])
+                       return 0;
+               else
+                       return 2;
+       }
+       else {
+               if(dim[1] > dim[2])
+                       return 1;
+               else
+                       return 2;
+       }
+}
+
+static void BBC_update_centroid(BBC *bbc)
+{
+       int i;
+       for(i = 0; i < 3; ++i)
+               bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
+}
+
+/* Not recursive */
+static void update_node_vb(PBVH *bvh, PBVHNode *node)
+{
+       BB vb;
+
+       BB_reset(&vb);
+       
+       if(node->flag & PBVH_Leaf) {
+               int i, totvert= node->uniq_verts + node->face_verts;
+
+               for(i = 0; i < totvert; ++i) {
+                       float *co= bvh->verts[node->vert_indices[i]].co;
+                       BB_expand(&vb, co);
+               }
+       }
+       else {
+               BB_expand_with_bb(&vb,
+                                 &bvh->nodes[node->children_offset].vb);
+               BB_expand_with_bb(&vb,
+                                 &bvh->nodes[node->children_offset + 1].vb);
+       }
+
+       node->vb= vb;
+}
+
+/* Adapted from BLI_kdopbvh.c */
+/* Returns the index of the first element on the right of the partition */
+static int partition_indices(int *face_indices, int lo, int hi, int axis,
+                            float mid, BBC *prim_bbc)
+{
+       int i=lo, j=hi;
+       for(;;) {
+               for(; prim_bbc[face_indices[i]].bcentroid[axis] < mid; i++);
+               for(; mid < prim_bbc[face_indices[j]].bcentroid[axis]; j--);
+               
+               if(!(i < j))
+                       return i;
+               
+               SWAP(int, face_indices[i], face_indices[j]);
+               i++;
+       }
+}
+
+void check_partitioning(int *face_indices, int lo, int hi, int axis,
+                              float mid, BBC *prim_bbc, int index_of_2nd_partition)
+{
+       int i;
+       for(i = lo; i <= hi; ++i) {
+               const float c = prim_bbc[face_indices[i]].bcentroid[axis];
+
+               if((i < index_of_2nd_partition && c > mid) ||
+                  (i > index_of_2nd_partition && c < mid)) {
+                       printf("fail\n");
+               }
+       }
+}
+
+static void grow_nodes(PBVH *bvh, int totnode)
+{
+       if(totnode > bvh->node_mem_count) {
+               PBVHNode *prev = bvh->nodes;
+               bvh->node_mem_count *= 1.33;
+               if(bvh->node_mem_count < totnode)
+                       bvh->node_mem_count = totnode;
+               bvh->nodes = MEM_callocN(sizeof(PBVHNode) * bvh->node_mem_count,
+                                        "bvh nodes");
+               memcpy(bvh->nodes, prev, bvh->totnode * sizeof(PBVHNode));
+               MEM_freeN(prev);
+       }
+
+       bvh->totnode = totnode;
+}
+
+/* Add a vertex to the map, with a positive value for unique vertices and
+   a negative value for additional vertices */
+static void map_insert_vert(PBVH *bvh, GHash *map,
+                           unsigned short *face_verts,
+                           unsigned short *uniq_verts, int vertex)
+{
+       void *value, *key = SET_INT_IN_POINTER(vertex);
+
+       if(!BLI_ghash_haskey(map, key)) {
+               if(BLI_bitmap_get(bvh->vert_bitmap, vertex)) {
+                       value = SET_INT_IN_POINTER(-(*face_verts) - 1);
+                       ++(*face_verts);
+               }
+               else {
+                       BLI_bitmap_set(bvh->vert_bitmap, vertex);
+                       value = SET_INT_IN_POINTER(*uniq_verts);
+                       ++(*uniq_verts);
+               }
+               
+               BLI_ghash_insert(map, key, value);
+       }
+}
+
+/* Find vertices used by the faces in this node and update the draw buffers */
+static void build_leaf_node(PBVH *bvh, PBVHNode *node)
+{
+       GHashIterator *iter;
+       GHash *map;
+       int i, j, totface;
+
+       map = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+       
+       node->uniq_verts = node->face_verts = 0;
+       totface= node->totface;
+
+       for(i = 0; i < totface; ++i) {
+               MFace *f = bvh->faces + node->face_indices[i];
+               int sides = f->v4 ? 4 : 3;
+
+               for(j = 0; j < sides; ++j) {
+                       map_insert_vert(bvh, map, &node->face_verts,
+                                       &node->uniq_verts, (&f->v1)[j]);
+               }
+       }
+
+       node->vert_indices = MEM_callocN(sizeof(int) *
+                                        (node->uniq_verts + node->face_verts),
+                                        "bvh node vert indices");
+
+       /* Build the vertex list, unique verts first */
+       for(iter = BLI_ghashIterator_new(map), i = 0;
+           !BLI_ghashIterator_isDone(iter);
+           BLI_ghashIterator_step(iter), ++i) {
+               void *value = BLI_ghashIterator_getValue(iter);
+               int ndx = GET_INT_FROM_POINTER(value);
+
+               if(ndx < 0)
+                       ndx = -ndx + node->uniq_verts - 1;
+
+               node->vert_indices[ndx] =
+                       GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(iter));
+       }
+
+       node->draw_buffers =
+               GPU_build_buffers(map, bvh->verts, bvh->faces,
+                                 node->face_indices,
+                                 node->totface, node->vert_indices,
+                                 node->uniq_verts,
+                                 node->uniq_verts + node->face_verts);
+
+       BLI_ghash_free(map, NULL, NULL);
+}
+
+/* Recursively build a node in the tree
+
+   vb is the voxel box around all of the primitives contained in
+   this node.
+
+   cb is the bounding box around all the centroids of the primitives
+   contained in this node
+
+   offset and start indicate a range in the array of primitive indices
+*/
+
+void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
+              int offset, int count)
+{
+       int i, axis, end;
+       BB cb_backing;
+
+       /* Decide whether this is a leaf or not */
+       if(count <= LEAF_LIMIT) {
+               bvh->nodes[node_index].flag |= PBVH_Leaf;
+
+               bvh->nodes[node_index].face_indices = bvh->face_indices + offset;
+               bvh->nodes[node_index].totface = count;
+
+               /* Still need vb for searches */
+               BB_reset(&bvh->nodes[node_index].vb);
+               for(i = offset + count - 1; i >= offset; --i) {
+                       BB_expand_with_bb(&bvh->nodes[node_index].vb,
+                                         (BB*)(prim_bbc +
+                                               bvh->face_indices[i]));
+               }
+               
+               build_leaf_node(bvh, bvh->nodes + node_index);
+
+               /* Done with this subtree */
+               return;
+       }
+       else {
+               BB_reset(&bvh->nodes[node_index].vb);
+               bvh->nodes[node_index].children_offset = bvh->totnode;
+               grow_nodes(bvh, bvh->totnode + 2);
+
+               if(!cb) {
+                       cb = &cb_backing;
+                       BB_reset(cb);
+                       for(i = offset + count - 1; i >= offset; --i)
+                               BB_expand(cb, prim_bbc[bvh->face_indices[i]].bcentroid);
+               }
+       }
+
+       axis = BB_widest_axis(cb);
+
+       for(i = offset + count - 1; i >= offset; --i) {
+               BB_expand_with_bb(&bvh->nodes[node_index].vb,
+                                 (BB*)(prim_bbc + bvh->face_indices[i]));
+       }
+
+       end = partition_indices(bvh->face_indices, offset, offset + count - 1,
+                               axis,
+                               (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
+                               prim_bbc);
+       check_partitioning(bvh->face_indices, offset, offset + count - 1,
+                          axis,
+                          (cb->bmax[axis] + cb->bmin[axis]) * 0.5f,
+                          prim_bbc, end);
+
+       build_sub(bvh, bvh->nodes[node_index].children_offset, NULL,
+                 prim_bbc, offset, end - offset);
+       build_sub(bvh, bvh->nodes[node_index].children_offset + 1, NULL,
+                 prim_bbc, end, offset + count - end);
+}
+
+/* Do a full rebuild */
+void BLI_pbvh_build(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert)
+{
+       BBC *prim_bbc = NULL;
+       BB cb;
+       int i, j;
+
+       if(totface != bvh->totface) {
+               bvh->totface = totface;
+               if(bvh->nodes) MEM_freeN(bvh->nodes);
+               if(bvh->face_indices) MEM_freeN(bvh->face_indices);
+               bvh->face_indices = MEM_callocN(sizeof(int) * totface,
+                                               "bvh face indices");
+               for(i = 0; i < totface; ++i)
+                       bvh->face_indices[i] = i;
+               bvh->totnode = 0;
+               if(bvh->node_mem_count < 100) {
+                       bvh->node_mem_count = 100;
+                       bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
+                                                bvh->node_mem_count,
+                                                "bvh initial nodes");
+               }
+       }
+
+       bvh->faces = faces;
+       bvh->verts = verts;
+       bvh->vert_bitmap = BLI_bitmap_new(totvert);
+       bvh->totvert= totvert;
+
+       BB_reset(&cb);
+
+       /* For each face, store the AABB and the AABB centroid */
+       prim_bbc = MEM_mallocN(sizeof(BBC) * totface, "prim_bbc");
+
+       for(i = 0; i < totface; ++i) {
+               MFace *f = faces + i;
+               const int sides = f->v4 ? 4 : 3;
+               BBC *bbc = prim_bbc + i;
+
+               BB_reset((BB*)bbc);
+
+               for(j = 0; j < sides; ++j)
+                       BB_expand((BB*)bbc, verts[(&f->v1)[j]].co);
+
+               BBC_update_centroid(bbc);
+
+               BB_expand(&cb, bbc->bcentroid);
+       }
+
+       bvh->totnode = 1;
+       build_sub(bvh, 0, &cb, prim_bbc, 0, totface);
+
+       MEM_freeN(prim_bbc);
+       MEM_freeN(bvh->vert_bitmap);
+}
+
+PBVH *BLI_pbvh_new(void)
+{
+       PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
+
+       return bvh;
+}
+
+void BLI_pbvh_free(PBVH *bvh)
+{
+       int i;
+
+       for(i = 0; i < bvh->totnode; ++i) {
+               if(bvh->nodes[i].flag & PBVH_Leaf) {
+                       GPU_free_buffers(bvh->nodes[i].draw_buffers);
+                       MEM_freeN(bvh->nodes[i].vert_indices);
+               }
+       }
+
+       MEM_freeN(bvh->nodes);
+       MEM_freeN(bvh->face_indices);
+       MEM_freeN(bvh);
+}
+
+void BLI_pbvh_set_source(PBVH *bvh, MVert *mvert, MFace *mface)
+{
+       bvh->verts = mvert;
+       bvh->faces = mface;
+}
+
+static void do_hit_callback(PBVH *bvh, PBVHNode *node,
+                           BLI_pbvh_HitCallback cb, void *data)
+{
+       if(cb)
+               cb(node, data);
+}
+
+static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data)
+{
+       iter->bvh= bvh;
+       iter->scb= scb;
+       iter->search_data= search_data;
+
+       iter->stack= iter->stackfixed;
+       iter->stackspace= STACK_FIXED_DEPTH;
+
+       iter->stack[0].node= bvh->nodes;
+       iter->stack[0].revisiting= 0;
+       iter->stacksize= 1;
+}
+
+static void pbvh_iter_end(PBVHIter *iter)
+{
+       if(iter->stackspace > STACK_FIXED_DEPTH)
+               MEM_freeN(iter->stack);
+}
+
+static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting)
+{
+       if(iter->stacksize == iter->stackspace) {
+               PBVHStack *newstack;
+
+               iter->stackspace *= 2;
+               newstack= MEM_callocN(sizeof(PBVHStack)*iter->stackspace, "PBVHStack");
+               memcpy(newstack, iter->stack, sizeof(PBVHStack)*iter->stacksize);
+
+               if(iter->stackspace > STACK_FIXED_DEPTH)
+                       MEM_freeN(iter->stack);
+               iter->stack= newstack;
+       }
+
+       iter->stack[iter->stacksize].node= node;
+       iter->stack[iter->stacksize].revisiting= revisiting;
+       iter->stacksize++;
+}
+
+static PBVHNode *pbvh_iter_next(PBVHIter *iter)
+{
+       PBVHNode *node;
+       int revisiting;
+       void *search_data;
+
+       /* purpose here is to traverse tree, visiting child nodes before their
+          parents, this order is necessary for e.g. computing bounding boxes */
+
+       while(iter->stacksize) {
+               /* pop node */
+               iter->stacksize--;
+               node= iter->stack[iter->stacksize].node;
+               revisiting= iter->stack[iter->stacksize].revisiting;
+
+               /* revisiting node already checked */
+               if(revisiting)
+                       return node;
+
+               /* check search callback */
+               search_data= iter->search_data;
+
+               if(iter->scb && !iter->scb(node, node->vb.bmin, node->vb.bmax, search_data))
+                       continue; /* don't traverse, outside of search zone */
+
+               if(node->flag & PBVH_Leaf) {
+                       /* immediately hit leaf node */
+                       return node;
+               }
+               else {
+                       /* come back later when children are done */
+                       pbvh_stack_push(iter, node, 1);
+
+                       /* push two child nodes on the stack */
+                       pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset+1, 0);
+                       pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset, 0);
+               }
+       }
+
+       return NULL;
+}
+
+void BLI_pbvh_search_gather(PBVH *bvh,
+       BLI_pbvh_SearchCallback scb, void *search_data,
+       PBVHNode ***r_array, int *r_tot)
+{
+       PBVHIter iter;
+       PBVHNode **array= NULL, **newarray, *node;
+       int tot= 0, space= 0;
+
+       pbvh_iter_begin(&iter, bvh, scb, search_data);
+
+       while((node=pbvh_iter_next(&iter))) {
+               if(node->flag & PBVH_Leaf) {
+                       if(tot == space) {
+                               /* resize array if needed */
+                               space= (tot == 0)? 32: space*2;
+                               newarray= MEM_callocN(sizeof(PBVHNode)*space, "PBVHNodeSearch");
+
+                               if(array) {
+                                       memcpy(newarray, array, sizeof(PBVHNode)*tot);
+                                       MEM_freeN(array);
+                               }
+
+                               array= newarray;
+                       }
+
+                       array[tot]= node;
+                       tot++;
+               }
+       }
+
+       pbvh_iter_end(&iter);
+
+       *r_array= array;
+       *r_tot= tot;
+}
+
+void BLI_pbvh_search_callback(PBVH *bvh,
+       BLI_pbvh_SearchCallback scb, void *search_data,
+       BLI_pbvh_HitCallback hcb, void *hit_data)
+{
+       PBVHIter iter;
+       PBVHNode *node;
+
+       pbvh_iter_begin(&iter, bvh, scb, search_data);
+
+       while((node=pbvh_iter_next(&iter)))
+               if(node->flag & PBVH_Leaf)
+                       do_hit_callback(bvh, node, hcb, hit_data);
+
+       pbvh_iter_end(&iter);
+}
+
+static int update_search_cb(PBVHNode *node,
+       float bb_min[3], float bb_max[3], void *data_v)
+{
+       if(node->flag & PBVH_Leaf)
+               return (node->flag & (PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw));
+       
+       return 1;
+}
+
+static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
+       int totnode, float (*face_nors)[3])
+{
+       float (*vnor)[3];
+       int n;
+
+       /* could be per node to save some memory, but also means
+          we have to store for each vertex which node it is in */
+       vnor= MEM_callocN(sizeof(float)*3*bvh->totvert, "bvh temp vnors");
+
+       /* subtle assumptions:
+          - We know that for all edited vertices, the nodes with faces
+            adjacent to these vertices have been marked with PBVH_UpdateNormals.
+                This is true because if the vertex is inside the brush radius, the
+                bounding box of it's adjacent faces will be as well.
+          - However this is only true for the vertices that have actually been
+            edited, not for all vertices in the nodes marked for update, so we
+                can only update vertices marked with ME_VERT_PBVH_UPDATE.
+       */
+
+       #pragma omp parallel for private(n) schedule(static)
+       for(n = 0; n < totnode; n++) {
+               PBVHNode *node= nodes[n];
+
+               if((node->flag & PBVH_UpdateNormals)) {
+                       int i, j, totface, *faces;
+
+                       BLI_pbvh_node_get_faces(node, &faces, &totface);
+
+                       for(i = 0; i < totface; ++i) {
+                               MFace *f= bvh->faces + faces[i];
+                               float fn[3];
+                               unsigned int *fv = &f->v1;
+                               int sides= (f->v4)? 4: 3;
+
+                               if(f->v4)
+                                       CalcNormFloat4(bvh->verts[f->v1].co, bvh->verts[f->v2].co,
+                                                                  bvh->verts[f->v3].co, bvh->verts[f->v4].co, fn);
+                               else
+                                       CalcNormFloat(bvh->verts[f->v1].co, bvh->verts[f->v2].co,
+                                                                 bvh->verts[f->v3].co, fn);
+
+                               for(j = 0; j < sides; ++j) {
+                                       int v= fv[j];
+
+                                       if(bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
+                                               /* this seems like it could be very slow but profile
+                                                  does not show this, so just leave it for now? */
+                                               #pragma omp atomic
+                                               vnor[v][0] += fn[0];
+                                               #pragma omp atomic
+                                               vnor[v][1] += fn[1];
+                                               #pragma omp atomic
+                                               vnor[v][2] += fn[2];
+                                       }
+                               }
+
+                               if(face_nors)
+                                       VECCOPY(face_nors[faces[i]], fn);
+                       }
+               }
+       }
+
+       #pragma omp parallel for private(n) schedule(static)
+       for(n = 0; n < totnode; n++) {
+               PBVHNode *node= nodes[n];
+
+               if(node->flag & PBVH_UpdateNormals) {
+                       int i, *verts, totvert;
+
+                       BLI_pbvh_node_get_verts(node, &verts, &totvert);
+
+                       for(i = 0; i < totvert; ++i) {
+                               const int v = verts[i];
+                               MVert *mvert= &bvh->verts[v];
+
+                               if(mvert->flag & ME_VERT_PBVH_UPDATE) {
+                                       float no[3];
+
+                                       VECCOPY(no, vnor[v]);
+                                       Normalize(no);
+                                       
+                                       mvert->no[0] = (short)(no[0]*32767.0f);
+                                       mvert->no[1] = (short)(no[1]*32767.0f);
+                                       mvert->no[2] = (short)(no[2]*32767.0f);
+                                       
+                                       mvert->flag &= ~ME_VERT_PBVH_UPDATE;
+                               }
+                       }
+
+                       node->flag &= ~PBVH_UpdateNormals;
+               }
+       }
+
+       MEM_freeN(vnor);
+}
+
+static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes,
+       int totnode, int flag)
+{
+       int n;
+
+       /* update BB, redraw flag */
+       #pragma omp parallel for private(n) schedule(static)
+       for(n = 0; n < totnode; n++) {
+               PBVHNode *node= nodes[n];
+
+               if((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB))
+                       /* don't clear flag yet, leave it for flushing later */
+                       update_node_vb(bvh, node);
+
+               if((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw))
+                       node->flag &= ~PBVH_UpdateRedraw;
+       }
+}
+
+static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
+{
+       PBVHNode *node;
+       int n;
+
+       /* can't be done in parallel with OpenGL */
+       for(n = 0; n < totnode; n++) {
+               node= nodes[n];
+
+               if(node->flag & PBVH_UpdateDrawBuffers) {
+                       GPU_update_buffers(node->draw_buffers,
+                                          bvh->verts,
+                                          node->vert_indices,
+                                          node->uniq_verts +
+                                          node->face_verts);
+
+                       node->flag &= ~PBVH_UpdateDrawBuffers;
+               }
+       }
+}
+
+static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node)
+{
+       int update= 0;
+
+       /* difficult to multithread well, we just do single threaded recursive */
+       if(node->flag & PBVH_Leaf) {
+               update= (node->flag & PBVH_UpdateBB);
+               node->flag &= ~PBVH_UpdateBB;
+               return update;
+       }
+       else {
+               update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset);
+               update |= pbvh_flush_bb(bvh, bvh->nodes + node->children_offset + 1);
+
+               if(update)
+                       update_node_vb(bvh, node);
+       }
+
+       return update;
+}
+
+void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3])
+{
+       PBVHNode **nodes;
+       int totnode;
+
+       BLI_pbvh_search_gather(bvh, update_search_cb, NULL, &nodes, &totnode);
+
+       if(flag & PBVH_UpdateNormals)
+               pbvh_update_normals(bvh, nodes, totnode, face_nors);
+
+       if(flag & (PBVH_UpdateBB|PBVH_UpdateRedraw))
+               pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
+
+       if(flag & PBVH_UpdateDrawBuffers)
+               pbvh_update_draw_buffers(bvh, nodes, totnode);
+
+       if(flag & PBVH_UpdateBB)
+               pbvh_flush_bb(bvh, bvh->nodes);
+
+       if(nodes) MEM_freeN(nodes);
+}
+
+void BLI_pbvh_redraw_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3])
+{
+       PBVHIter iter;
+       PBVHNode *node;
+       BB bb;
+
+       BB_reset(&bb);
+
+       pbvh_iter_begin(&iter, bvh, NULL, NULL);
+
+       while((node=pbvh_iter_next(&iter)))
+               if(node->flag & PBVH_UpdateRedraw)
+                       BB_expand_with_bb(&bb, &node->vb);
+
+       pbvh_iter_end(&iter);
+
+       VecCopyf(bb_min, bb.bmin);
+       VecCopyf(bb_max, bb.bmax);
+}
+
+/***************************** Node Access ***********************************/
+
+void BLI_pbvh_node_mark_update(PBVHNode *node)
+{
+       node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw;
+}
+
+void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert)
+{
+       *vert_indices= node->vert_indices;
+       *totvert= node->uniq_verts;
+}
+
+void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int *totface)
+{
+       *face_indices= node->face_indices;
+       *totface= node->totface;
+}
+
+void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node)
+{
+       return node->draw_buffers;
+}
+
+/********************************* Raycast ***********************************/
+
+typedef struct {
+       /* Ray */
+       float start[3];
+       int sign[3];
+       float inv_dir[3];
+} RaycastData;
+
+/* Adapted from here: http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
+static int ray_aabb_intersect(PBVHNode *node, float bb_min[3], float bb_max[3], void *data_v)
+{
+       RaycastData *ray = data_v;
+       float bbox[2][3];
+       float tmin, tmax, tymin, tymax, tzmin, tzmax;
+
+       VecCopyf(bbox[0], bb_min);
+       VecCopyf(bbox[1], bb_max);
+
+       tmin = (bbox[ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
+       tmax = (bbox[1-ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
+
+       tymin = (bbox[ray->sign[1]][1] - ray->start[1]) * ray->inv_dir[1];
+       tymax = (bbox[1-ray->sign[1]][1] - ray->start[1]) * ray->inv_dir[1];
+
+       if((tmin > tymax) || (tymin > tmax))
+               return 0;
+       if(tymin > tmin)
+               tmin = tymin;
+       if(tymax < tmax)
+               tmax = tymax;
+
+       tzmin = (bbox[ray->sign[2]][2] - ray->start[2]) * ray->inv_dir[2];
+       tzmax = (bbox[1-ray->sign[2]][2] - ray->start[2]) * ray->inv_dir[2];
+
+       if((tmin > tzmax) || (tzmin > tmax))
+               return 0;
+
+       return 1;
+
+       /* XXX: Not sure about this? 
+          if(tzmin > tmin)
+          tmin = tzmin;
+          if(tzmax < tmax)
+          tmax = tzmax;
+          return ((tmin < t1) && (tmax > t0));
+       */
+
+}
+
+void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+                     float ray_start[3], float ray_normal[3])
+{
+       RaycastData rcd;
+
+       VecCopyf(rcd.start, ray_start);
+       rcd.inv_dir[0] = 1.0f / ray_normal[0];
+       rcd.inv_dir[1] = 1.0f / ray_normal[1];
+       rcd.inv_dir[2] = 1.0f / ray_normal[2];
+       rcd.sign[0] = rcd.inv_dir[0] < 0;
+       rcd.sign[1] = rcd.inv_dir[1] < 0;
+       rcd.sign[2] = rcd.inv_dir[2] < 0;
+
+       BLI_pbvh_search_callback(bvh, ray_aabb_intersect, &rcd, cb, data);
+}
+
index 764efb4ef0c0f2765afaebc6cf84a54b5bc73922..085c8e894f84ad96c721231b6c0182ffee284dba 100644 (file)
 #ifndef ED_SCULPT_H
 #define ED_SCULPT_H
 
+struct ARegion;
 struct bContext;
+struct Object;
+struct RegionView3D;
 struct wmKeyConfig;
+struct wmWindowManager;
 
 /* sculpt.c */
 void ED_operatortypes_sculpt(void);
+void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
+                             struct RegionView3D *rv3d, struct Object *ob);
+
 
 /* paint_ops.c */
 void ED_operatortypes_paint(void);
 void ED_keymap_paint(struct wmKeyConfig *keyconf);
 
-/* paint_image.c */
-void undo_imagepaint_step(int step);
-void undo_imagepaint_clear(void);
+/* paint_undo.c */
+#define UNDO_PAINT_IMAGE       0
+#define UNDO_PAINT_MESH                1
+
+void ED_undo_paint_step(struct bContext *C, int type, int step);
+void ED_undo_paint_free(void);
 
 #endif
index 2ec9ddf6c5280f3f9df2c59804389e4353f46a88..e8dd27bbdb7068f78d9d35ef09e8561ee7a0f3aa 100644 (file)
@@ -30,6 +30,7 @@
 
 /* ********* exports for space_view3d/ module ********** */
 struct ARegion;
+struct BoundBox;
 struct View3D;
 struct RegionView3D;
 struct ViewContext;
@@ -44,6 +45,7 @@ struct ImBuf;
 struct Scene;
 struct bContext;
 struct Main;
+struct rcti;
 
 /* for derivedmesh drawing callbacks, for view3d_select, .... */
 typedef struct ViewContext {
@@ -80,6 +82,8 @@ void request_depth_update(struct RegionView3D *rv3d);
 /* Projection */
 #define IS_CLIPPED        12000
 
+void view3d_calculate_clipping(struct BoundBox *bb, float planes[4][4], struct bglMats *mats, struct rcti *rect);
+
 void project_short(struct ARegion *ar, float *vec, short *adr);
 void project_short_noclip(struct ARegion *ar, float *vec, short *adr);
 
@@ -125,7 +129,7 @@ short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigne
 void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
 void view3d_operator_needs_opengl(const struct bContext *C);
 void view3d_get_view_aligned_coordinate(struct ViewContext *vc, float *fp, short mval[2]);
-void view3d_get_transformation(struct ViewContext *vc, struct Object *ob, struct bglMats *mats);
+void view3d_get_transformation(struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
 
 /* XXX should move to arithb.c */
 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2);
index 1b0dc95480ac42c03e511d2de2517ea3ebadea55..39a8a026afbb4941d32e40d27d13dded02858c3c 100644 (file)
@@ -718,6 +718,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
        MultiresModifierData *mmd= ptr.data;
 
        multiresModifier_subdivide(mmd, ob, 1, 0, mmd->simple);
+
+       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
        
        return OPERATOR_FINISHED;
index 438150b25ac0f729fa3194ffaef7acc48fa7a60b..d4a6a719de0cd5526979c96c629ad56d8410d33e 100644 (file)
@@ -362,7 +362,7 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
        PE_set_data(C, data);
 
        view3d_set_viewcontext(C, &data->vc);
-       view3d_get_transformation(&data->vc, data->ob, &data->mats);
+       view3d_get_transformation(data->vc.ar, data->vc.rv3d, data->ob, &data->mats);
 
        if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
                view3d_validate_backbuf(&data->vc);
index 929f854242f7c36a2df9fc468d3e49b07f1e9944..d8c4d505fc9017a583dd4e3547d8d369b7d3dac2 100644 (file)
@@ -86,6 +86,7 @@
 #include "ED_image.h"
 #include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 #include "ED_view3d.h"
 
 #include "WM_api.h"
 #define IMAPAINT_TILE_SIZE                     (1 << IMAPAINT_TILE_BITS)
 #define IMAPAINT_TILE_NUMBER(size)     (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
 
-#define MAXUNDONAME    64
-
 static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint);
 
 
@@ -204,7 +203,7 @@ typedef struct ProjPaintImage {
        Image *ima;
        ImBuf *ibuf;
        ImagePaintPartialRedraw *partRedrawRect;
-       struct UndoTile **undoRect; /* only used to build undo tiles after painting */
+       void **undoRect; /* only used to build undo tiles after painting */
        int touch;
 } ProjPaintImage;
 
@@ -332,32 +331,20 @@ typedef struct ProjPixelClone {
 
 /* Finish projection painting structs */
 
+typedef struct UndoImageTile {
+       struct UndoImageTile *next, *prev;
+
+       char idname[MAX_ID_NAME];       /* name instead of pointer*/
 
-typedef struct UndoTile {
-       struct UndoTile *next, *prev;
-       ID id;
        void *rect;
        int x, y;
-} UndoTile;
-
-typedef struct UndoElem {
-       struct UndoElem *next, *prev;
-       char name[MAXUNDONAME];
-       uintptr_t undosize;
+} UndoImageTile;
 
-       ImBuf *ibuf;
-       ListBase tiles;
-} UndoElem;
-
-static ListBase undobase = {NULL, NULL};
-static UndoElem *curundo = NULL;
 static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
 
 /* UNDO */
 
-/* internal functions */
-
-static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
 {
        /* copy or swap contents of tile->rect and region in ibuf->rect */
        IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x*IMAPAINT_TILE_SIZE,
@@ -374,49 +361,52 @@ static void undo_copy_tile(UndoTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int rest
                        tile->y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
 }
 
-static UndoTile *undo_init_tile(ID *id, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
+static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
 {
-       UndoTile *tile;
+       ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       UndoImageTile *tile;
        int allocsize;
+
+       for(tile=lb->first; tile; tile=tile->next)
+               if(tile->x == x_tile && tile->y == y_tile && strcmp(tile->idname, ima->id.name)==0)
+                       return tile->rect;
        
        if (*tmpibuf==NULL)
                *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0);
        
-       tile= MEM_callocN(sizeof(UndoTile), "ImaUndoTile");
-       tile->id= *id;
+       tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+       strcpy(tile->idname, ima->id.name);
        tile->x= x_tile;
        tile->y= y_tile;
 
        allocsize= IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE*4;
        allocsize *= (ibuf->rect_float)? sizeof(float): sizeof(char);
-       tile->rect= MEM_mapallocN(allocsize, "ImaUndoRect");
+       tile->rect= MEM_mapallocN(allocsize, "UndeImageTile.rect");
 
        undo_copy_tile(tile, *tmpibuf, ibuf, 0);
-       curundo->undosize += allocsize;
+       undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
 
-       BLI_addtail(&curundo->tiles, tile);
+       BLI_addtail(lb, tile);
        
-       return tile;
+       return tile->rect;
 }
 
-static void undo_restore(UndoElem *undo)
+static void image_undo_restore(bContext *C, ListBase *lb)
 {
+       Main *bmain= CTX_data_main(C);
        Image *ima = NULL;
        ImBuf *ibuf, *tmpibuf;
-       UndoTile *tile;
-
-       if(!undo)
-               return;
+       UndoImageTile *tile;
 
        tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
                                IB_rectfloat|IB_rect, 0);
        
-       for(tile=undo->tiles.first; tile; tile=tile->next) {
+       for(tile=lb->first; tile; tile=tile->next) {
                /* find image based on name, pointer becomes invalid with global undo */
-               if(ima && strcmp(tile->id.name, ima->id.name)==0);
+               if(ima && strcmp(tile->idname, ima->id.name)==0);
                else {
-                       for(ima=G.main->image.first; ima; ima=ima->id.next)
-                               if(strcmp(tile->id.name, ima->id.name)==0)
+                       for(ima=bmain->image.first; ima; ima=ima->id.next)
+                               if(strcmp(tile->idname, ima->id.name)==0)
                                        break;
                }
 
@@ -435,117 +425,12 @@ static void undo_restore(UndoElem *undo)
        IMB_freeImBuf(tmpibuf);
 }
 
-static void undo_free(UndoElem *undo)
+static void image_undo_free(ListBase *lb)
 {
-       UndoTile *tile;
+       UndoImageTile *tile;
 
-       for(tile=undo->tiles.first; tile; tile=tile->next)
+       for(tile=lb->first; tile; tile=tile->next)
                MEM_freeN(tile->rect);
-       BLI_freelistN(&undo->tiles);
-}
-
-static void undo_imagepaint_push_begin(char *name)
-{
-       UndoElem *uel;
-       int nr;
-       
-       /* Undo push is split up in begin and end, the reason is that as painting
-        * happens more tiles are added to the list, and at the very end we know
-        * how much memory the undo used to remove old undo elements */
-
-       /* remove all undos after (also when curundo==NULL) */
-       while(undobase.last != curundo) {
-               uel= undobase.last;
-               undo_free(uel);
-               BLI_freelinkN(&undobase, uel);
-       }
-       
-       /* make new */
-       curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
-       BLI_addtail(&undobase, uel);
-
-       /* name can be a dynamic string */
-       strncpy(uel->name, name, MAXUNDONAME-1);
-       
-       /* limit amount to the maximum amount*/
-       nr= 0;
-       uel= undobase.last;
-       while(uel) {
-               nr++;
-               if(nr==U.undosteps) break;
-               uel= uel->prev;
-       }
-       if(uel) {
-               while(undobase.first!=uel) {
-                       UndoElem *first= undobase.first;
-                       undo_free(first);
-                       BLI_freelinkN(&undobase, first);
-               }
-       }
-}
-
-static void undo_imagepaint_push_end()
-{
-       UndoElem *uel;
-       uintptr_t totmem, maxmem;
-
-       if(U.undomemory != 0) {
-               /* limit to maximum memory (afterwards, we can't know in advance) */
-               totmem= 0;
-               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
-
-               uel= undobase.last;
-               while(uel) {
-                       totmem+= uel->undosize;
-                       if(totmem>maxmem) break;
-                       uel= uel->prev;
-               }
-
-               if(uel) {
-                       while(undobase.first!=uel) {
-                               UndoElem *first= undobase.first;
-                               undo_free(first);
-                               BLI_freelinkN(&undobase, first);
-                       }
-               }
-       }
-}
-
-void undo_imagepaint_step(int step)
-{
-       UndoElem *undo;
-
-       if(step==1) {
-               if(curundo==NULL);
-               else {
-                       if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
-                       undo_restore(curundo);
-                       curundo= curundo->prev;
-               }
-       }
-       else if(step==-1) {
-               if((curundo!=NULL && curundo->next==NULL) || undobase.first==NULL);
-               else {
-                       undo= (curundo && curundo->next)? curundo->next: undobase.first;
-                       undo_restore(undo);
-                       curundo= undo;
-                       if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
-               }
-       }
-}
-
-void undo_imagepaint_clear(void)
-{
-       UndoElem *uel;
-       
-       uel= undobase.first;
-       while(uel) {
-               undo_free(uel);
-               uel= uel->next;
-       }
-
-       BLI_freelistN(&undobase);
-       curundo= NULL;
 }
 
 /* fast projection bucket array lookup, use the safe version for bound checking  */
@@ -3316,7 +3201,7 @@ static void project_paint_end(ProjPaintState *ps)
                ProjPixel *projPixel;
                ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
                LinkNode *pixel_node;
-               UndoTile *tile;
+               void *tilerect;
                MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
                                
                int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
@@ -3332,8 +3217,8 @@ static void project_paint_end(ProjPaintState *ps)
                int last_tile_width=0;
                
                for(a=0, last_projIma=ps->projImages; a < ps->image_tot; a++, last_projIma++) {
-                       int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
-                       last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size);
+                       int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
+                       last_projIma->undoRect = (void **) BLI_memarena_alloc(arena, size);
                        memset(last_projIma->undoRect, 0, size);
                        last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
                }
@@ -3373,21 +3258,21 @@ static void project_paint_end(ProjPaintState *ps)
                                        
                                        if (last_projIma->undoRect[tile_index]==NULL) {
                                                /* add the undo tile from the modified image, then write the original colors back into it */
-                                               tile = last_projIma->undoRect[tile_index] = undo_init_tile(&last_projIma->ima->id, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
+                                               tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float):(&tmpibuf) , x_tile, y_tile);
                                        }
                                        else {
-                                               tile = last_projIma->undoRect[tile_index];
+                                               tilerect = last_projIma->undoRect[tile_index];
                                        }
                                        
                                        /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
                                         * because allocating the tiles allong the way slows down painting */
                                        
                                        if (is_float) {
-                                               float *rgba_fp = (float *)tile->rect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
+                                               float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
                                                QUATCOPY(rgba_fp, projPixel->origColor.f);
                                        }
                                        else {
-                                               ((unsigned int *)tile->rect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
+                                               ((unsigned int *)tilerect)[ (projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE ] = projPixel->origColor.uint;
                                        }
                                }
                        }
@@ -3958,7 +3843,6 @@ static void imapaint_clear_partial_redraw()
 static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
 {
        ImBuf *tmpibuf = NULL;
-       UndoTile *tile;
        int srcx= 0, srcy= 0, origx;
 
        IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@@ -3985,17 +3869,9 @@ static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w,
        origx = (x >> IMAPAINT_TILE_BITS);
        y = (y >> IMAPAINT_TILE_BITS);
        
-       for (; y <= h; y++) {
-               for (x=origx; x <= w; x++) {
-                       for(tile=curundo->tiles.first; tile; tile=tile->next)
-                               if(tile->x == x && tile->y == y && strcmp(tile->id.name, ima->id.name)==0)
-                                       break;
-
-                       if(!tile) {
-                               undo_init_tile(&ima->id, ibuf, &tmpibuf, x, y);
-                       }
-               }
-       }
+       for (; y <= h; y++)
+               for (x=origx; x <= w; x++)
+                       image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
 
        ibuf->userflags |= IB_BITMAPDIRTY;
        
@@ -4593,7 +4469,8 @@ static int texture_paint_init(bContext *C, wmOperator *op)
        }
        
        settings->imapaint.flag |= IMAGEPAINT_DRAWING;
-       undo_imagepaint_push_begin("Image Paint");
+       undo_paint_push_begin(UNDO_PAINT_IMAGE, "Image Paint",
+               image_undo_restore, image_undo_free);
 
        /* create painter */
        pop->painter= brush_painter_new(pop->s.brush);
@@ -4657,7 +4534,7 @@ static void paint_exit(bContext *C, wmOperator *op)
        }
        
        paint_redraw(C, &pop->s, 1);
-       undo_imagepaint_push_end();
+       undo_paint_push_end(UNDO_PAINT_IMAGE);
        
        if(pop->s.warnmultifile)
                BKE_reportf(op->reports, RPT_WARNING, "Image requires 4 color channels to paint: %s", pop->s.warnmultifile);
@@ -5256,3 +5133,4 @@ int facemask_paint_poll(bContext *C)
 {
        return paint_facesel_test(CTX_data_active_object(C));
 }
+
index b5748d7bc88863f6fce7369666f5b50fa77d390e..46f073243e55eacd8853f8c1cebf1539e0be7038 100644 (file)
@@ -41,13 +41,16 @@ struct wmOperator;
 struct wmOperatorType;
 struct ARegion;
 struct VPaint;
+struct ListBase;
 
 /* paint_stroke.c */
+typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
 typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
 typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
 typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke);
 
-struct PaintStroke *paint_stroke_new(struct bContext *C, StrokeTestStart test_start,
+struct PaintStroke *paint_stroke_new(struct bContext *C,
+                                    StrokeGetLocation get_location, StrokeTestStart test_start,
                                     StrokeUpdateStep update_step, StrokeDone done);
 int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
 int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
@@ -100,5 +103,14 @@ void PAINT_OT_face_deselect_all(struct wmOperatorType *ot);
 
 int facemask_paint_poll(struct bContext *C);
 
+/* paint_undo.c */
+typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
+typedef void (*UndoFreeCb)(struct ListBase *lb);
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free);
+struct ListBase *undo_paint_push_get_list(int type);
+void undo_paint_push_count_alloc(int type, int size);
+void undo_paint_push_end(int type);
+
 #endif /* ED_PAINT_INTERN_H */
 
index 6e256bee7f27d285b11f40d896253cc673fc42c4..6d7fd82653498d465cfe091c9e76541cc3cee50e 100644 (file)
@@ -73,6 +73,7 @@ typedef struct PaintStroke {
           passes over the mesh */
        int stroke_started;
 
+       StrokeGetLocation get_location;
        StrokeTestStart test_start;
        StrokeUpdateStep update_step;
        StrokeDone done;
@@ -100,7 +101,11 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
 
 static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
 {
-       Brush *brush = paint_brush(paint_get_active(CTX_data_scene(C)));
+       Paint *paint = paint_get_active(CTX_data_scene(C));
+       Brush *brush = paint_brush(paint);
+
+       if(!(paint->flags & PAINT_SHOW_BRUSH))
+               return;
 
        glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
        glEnable(GL_LINE_SMOOTH);
@@ -118,12 +123,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
 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};
        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) {
@@ -208,15 +214,19 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
 
 /**** Public API ****/
 
-PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
-                             StrokeUpdateStep update_step, StrokeDone done)
+PaintStroke *paint_stroke_new(bContext *C,
+                             StrokeGetLocation get_location,
+                             StrokeTestStart test_start,
+                             StrokeUpdateStep update_step,
+                             StrokeDone done)
 {
        PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
 
        stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C)));
        view3d_set_viewcontext(C, &stroke->vc);
-       view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats);
+       view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
 
+       stroke->get_location = get_location;
        stroke->test_start = test_start;
        stroke->update_step = update_step;
        stroke->done = done;
@@ -226,12 +236,9 @@ PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start,
 
 int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
 {
-       ARegion *ar = CTX_wm_region(C);
        PaintStroke *stroke = op->customdata;
        float mouse[2];
-
-       if(event->type == TIMER && (event->customdata != stroke->timer))
-               return OPERATOR_RUNNING_MODAL;
+       int first= 0;
 
        if(!stroke->stroke_started) {
                stroke->last_mouse_position[0] = event->x;
@@ -246,26 +253,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
                                stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
                }
 
-               ED_region_tag_redraw(ar);
-       }
-
-       if(stroke->stroke_started) {
-               if(paint_smooth_stroke(stroke, mouse, event)) {
-                       if(paint_space_stroke_enabled(stroke->brush)) {
-                               if(!paint_space_stroke(C, op, event, mouse))
-                                       ED_region_tag_redraw(ar);
-                       }
-                       else
-                               paint_brush_stroke_add_step(C, op, event, mouse);
-               }
-               else
-                       ED_region_tag_redraw(ar);
+               first= 1;
+               //ED_region_tag_redraw(ar);
        }
 
-       /* TODO: fix hardcoded event here */
+       /* TODO: fix hardcoded events here */
        if(event->type == LEFTMOUSE && event->val == KM_RELEASE) {
-               /* Exit stroke, free data */
-
+               /* exit stroke, free data */
                if(stroke->smooth_stroke_cursor)
                        WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
 
@@ -276,8 +270,22 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
                MEM_freeN(stroke);
                return OPERATOR_FINISHED;
        }
-       else
-               return OPERATOR_RUNNING_MODAL;
+       else if(first || event->type == MOUSEMOVE || (event->type == TIMER && (event->customdata == stroke->timer))) {
+               if(stroke->stroke_started) {
+                       if(paint_smooth_stroke(stroke, mouse, event)) {
+                               if(paint_space_stroke_enabled(stroke->brush)) {
+                                       if(!paint_space_stroke(C, op, event, mouse))
+                                               ;//ED_region_tag_redraw(ar);
+                               }
+                               else
+                                       paint_brush_stroke_add_step(C, op, event, mouse);
+                       }
+                       else
+                               ;//ED_region_tag_redraw(ar);
+               }
+       }
+
+       return OPERATOR_RUNNING_MODAL;
 }
 
 int paint_stroke_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
new file mode 100644 (file)
index 0000000..9bc6cac
--- /dev/null
@@ -0,0 +1,231 @@
+/**
+ * $Id$
+ *
+ * Undo system for painting and sculpting.
+ * 
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA       02111-1307, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "ED_sculpt.h"
+
+#include "paint_intern.h"
+
+#define MAXUNDONAME    64
+
+typedef struct UndoElem {
+       struct UndoElem *next, *prev;
+       char name[MAXUNDONAME];
+       uintptr_t undosize;
+
+       ListBase elems;
+
+       UndoRestoreCb restore;
+       UndoFreeCb free;
+} UndoElem;
+
+typedef struct UndoStack {
+       int type;
+       ListBase elems;
+       UndoElem *current;
+} UndoStack;
+
+static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
+static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
+
+/* Generic */
+
+static void undo_restore(bContext *C, UndoStack *stack, UndoElem *uel)
+{
+       if(uel && uel->restore)
+               uel->restore(C, &uel->elems);
+}
+
+static void undo_elem_free(UndoStack *stack, UndoElem *uel)
+{
+       if(uel && uel->free) {
+               uel->free(&uel->elems);
+               BLI_freelistN(&uel->elems);
+       }
+}
+
+static void undo_stack_push_begin(UndoStack *stack, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+       UndoElem *uel;
+       int nr;
+       
+       /* Undo push is split up in begin and end, the reason is that as painting
+        * happens more tiles/nodes are added to the list, and at the very end we
+        * know how much memory the undo used to remove old undo elements */
+
+       /* remove all undos after (also when stack->current==NULL) */
+       while(stack->elems.last != stack->current) {
+               uel= stack->elems.last;
+               undo_elem_free(stack, uel);
+               BLI_freelinkN(&stack->elems, uel);
+       }
+       
+       /* make new */
+       stack->current= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+       uel->restore= restore;
+       uel->free= free;
+       BLI_addtail(&stack->elems, uel);
+
+       /* name can be a dynamic string */
+       strncpy(uel->name, name, MAXUNDONAME-1);
+       
+       /* limit amount to the maximum amount*/
+       nr= 0;
+       uel= stack->elems.last;
+       while(uel) {
+               nr++;
+               if(nr==U.undosteps) break;
+               uel= uel->prev;
+       }
+       if(uel) {
+               while(stack->elems.first!=uel) {
+                       UndoElem *first= stack->elems.first;
+                       undo_elem_free(stack, first);
+                       BLI_freelinkN(&stack->elems, first);
+               }
+       }
+}
+
+static void undo_stack_push_end(UndoStack *stack)
+{
+       UndoElem *uel;
+       uintptr_t totmem, maxmem;
+
+       if(U.undomemory != 0) {
+               /* limit to maximum memory (afterwards, we can't know in advance) */
+               totmem= 0;
+               maxmem= ((uintptr_t)U.undomemory)*1024*1024;
+
+               uel= stack->elems.last;
+               while(uel) {
+                       totmem+= uel->undosize;
+                       if(totmem>maxmem) break;
+                       uel= uel->prev;
+               }
+
+               if(uel) {
+                       while(stack->elems.first!=uel) {
+                               UndoElem *first= stack->elems.first;
+                               undo_elem_free(stack, first);
+                               BLI_freelinkN(&stack->elems, first);
+                       }
+               }
+       }
+}
+
+static void undo_stack_step(bContext *C, UndoStack *stack, int step)
+{
+       UndoElem *undo;
+
+       if(step==1) {
+               if(stack->current==NULL);
+               else {
+                       if(G.f & G_DEBUG) printf("undo %s\n", stack->current->name);
+                       undo_restore(C, stack, stack->current);
+                       stack->current= stack->current->prev;
+               }
+       }
+       else if(step==-1) {
+               if((stack->current!=NULL && stack->current->next==NULL) || stack->elems.first==NULL);
+               else {
+                       undo= (stack->current && stack->current->next)? stack->current->next: stack->elems.first;
+                       undo_restore(C, stack, undo);
+                       stack->current= undo;
+                       if(G.f & G_DEBUG) printf("redo %s\n", undo->name);
+               }
+       }
+}
+
+static void undo_stack_free(UndoStack *stack)
+{
+       UndoElem *uel;
+       
+       for(uel=stack->elems.first; uel; uel=uel->next)
+               undo_elem_free(stack, uel);
+
+       BLI_freelistN(&stack->elems);
+       stack->current= NULL;
+}
+
+/* Exported Functions */
+
+void undo_paint_push_begin(int type, char *name, UndoRestoreCb restore, UndoFreeCb free)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_push_begin(&ImageUndoStack, name, restore, free);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_push_begin(&MeshUndoStack, name, restore, free);
+}
+
+ListBase *undo_paint_push_get_list(int type)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               return &ImageUndoStack.current->elems;
+       else if(type == UNDO_PAINT_MESH)
+               return &MeshUndoStack.current->elems;
+       
+       return NULL;
+}
+
+void undo_paint_push_count_alloc(int type, int size)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               ImageUndoStack.current->undosize += size;
+       else if(type == UNDO_PAINT_MESH)
+               MeshUndoStack.current->undosize += size;
+}
+
+void undo_paint_push_end(int type)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_push_end(&ImageUndoStack);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_push_end(&MeshUndoStack);
+}
+
+void ED_undo_paint_step(bContext *C, int type, int step)
+{
+       if(type == UNDO_PAINT_IMAGE)
+               undo_stack_step(C, &ImageUndoStack, step);
+       else if(type == UNDO_PAINT_MESH)
+               undo_stack_step(C, &MeshUndoStack, step);
+}
+
+void ED_undo_paint_free(void)
+{
+       undo_stack_free(&ImageUndoStack);
+       undo_stack_free(&MeshUndoStack);
+}
+
index 151040683509f71146168350447a846d00e59e2c..210d6e0ff953e156e9c6a36f4a9debac8f27fa39 100644 (file)
@@ -96,7 +96,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
        int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
        MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
-       int numfaces = dm->getNumFaces(dm), a;
+       int numfaces = dm->getNumFaces(dm), a, findex;
        float p[2], w[3], absw, minabsw;
        MFace mf;
        MVert mv[4];
@@ -106,7 +106,9 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind
 
        /* test all faces in the derivedmesh with the original index of the picked face */
        for(a = 0; a < numfaces; a++) {
-               if(index[a] == faceindex) {
+               findex= (index)? index[a]: a;
+
+               if(findex == faceindex) {
                        dm->getFace(dm, a, &mf);
 
                        dm->getVert(dm, mf.v1, &mv[0]);
index 408f4862b6f284efdfc53a25227e5d3a3cf21e1a..582a0c149b407285ea5034dc54c29735ee3126e1 100644 (file)
@@ -1610,7 +1610,7 @@ static void wpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
 static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        
-       op->customdata = paint_stroke_new(C, wpaint_stroke_test_start,
+       op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
                                          wpaint_stroke_update_step,
                                          wpaint_stroke_done);
        
@@ -1909,7 +1909,7 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
 static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        
-       op->customdata = paint_stroke_new(C, vpaint_stroke_test_start,
+       op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
                                          vpaint_stroke_update_step,
                                          vpaint_stroke_done);
        
index c4c7f436f12d822dfa3bbd35afde49f367c164d0..fd614555fcb55ceef69301653b82da7ed61dceac 100644 (file)
@@ -35,6 +35,9 @@
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
 #include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
+#include "BLI_threads.h"
 
 #include "DNA_armature_types.h"
 #include "DNA_brush_types.h"
@@ -52,6 +55,7 @@
 #include "DNA_color_types.h"
 
 #include "BKE_brush.h"
+#include "BKE_cdderivedmesh.h"
 #include "BKE_context.h"
 #include "BKE_customdata.h"
 #include "BKE_DerivedMesh.h"
@@ -131,7 +135,6 @@ typedef struct StrokeCache {
        int flag;
        float clip_tolerance[3];
        float initial_mouse[2];
-       float depth;
 
        /* Variants */
        float radius;
@@ -140,6 +143,7 @@ typedef struct StrokeCache {
        float flip;
        float pressure;
        float mouse[2];
+       float bstrength;
 
        /* The rest is temporary storage that isn't saved as a property */
 
@@ -147,11 +151,17 @@ typedef struct StrokeCache {
 
        bglMats *mats;
 
+       /* Clean this up! */
+       ViewContext *vc;
+       Brush *brush;
+
        short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */
        float (*face_norms)[3]; /* Copy of the mesh faces' normals */
        float rotation; /* Texture rotation (radians) for anchored and rake modes */
        int pixel_radius, previous_pixel_radius;
-       ListBase grab_active_verts[8]; /* The same list of verts is used throught grab stroke */
+       PBVHNode **grab_active_nodes[8]; /* The same list of nodes is used throught grab stroke */
+       int grab_active_totnode[8];
+       float grab_active_location[8][3];
        float grab_delta[3], grab_delta_symmetry[3];
        float old_grab_location[3];
        int symmetry; /* Symmetry index between 0 and 7 */
@@ -159,20 +169,6 @@ typedef struct StrokeCache {
        int last_rake[2]; /* Last location of updating rake rotation */
 } StrokeCache;
 
-typedef struct RectNode {
-       struct RectNode *next, *prev;
-       rcti r;
-} RectNode;
-
-/* Used to store to 2D screen coordinates of each vertex in the mesh. */
-typedef struct ProjVert {
-       short co[2];
-       
-       /* Used to mark whether a vertex is inside a rough bounding box
-          containing the brush. */
-       char inside;
-} ProjVert;
-
 /* ===== OPENGL =====
  *
  * Simple functions to get data from the GL
@@ -189,7 +185,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
        p[1]= uy;
 }
 
-static void project(bglMats *mats, const float v[3], short p[2])
+/*XXX: static void project(bglMats *mats, const float v[3], short p[2])
 {
        float f[2];
        projectf(mats, v, f);
@@ -197,6 +193,262 @@ static void project(bglMats *mats, const float v[3], short p[2])
        p[0]= f[0];
        p[1]= f[1];
 }
+*/
+
+/*** BVH Tree ***/
+
+/* Get a screen-space rectangle of the modified area */
+int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
+                           Object *ob, rcti *rect)
+{
+       float bb_min[3], bb_max[3], pmat[4][4];
+       int i, j, k;
+
+       view3d_get_object_project_mat(rv3d, ob, pmat);
+
+       BLI_pbvh_redraw_bounding_box(ob->sculpt->tree, bb_min, bb_max);
+
+       rect->xmin = rect->ymin = INT_MAX;
+       rect->xmax = rect->ymax = INT_MIN;
+
+       if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
+               return 0;
+
+       for(i = 0; i < 2; ++i) {
+               for(j = 0; j < 2; ++j) {
+                       for(k = 0; k < 2; ++k) {
+                               float vec[3], proj[2];
+                               vec[0] = i ? bb_min[0] : bb_max[0];
+                               vec[1] = j ? bb_min[1] : bb_max[1];
+                               vec[2] = k ? bb_min[2] : bb_max[2];
+                               view3d_project_float(ar, vec, proj, pmat);
+                               rect->xmin = MIN2(rect->xmin, proj[0]);
+                               rect->xmax = MAX2(rect->xmax, proj[0]);
+                               rect->ymin = MIN2(rect->ymin, proj[1]);
+                               rect->ymax = MAX2(rect->ymax, proj[1]);
+                       }
+               }
+       }
+       
+       return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
+}
+
+void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
+                             RegionView3D *rv3d, Object *ob)
+{
+       BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox");
+       bglMats mats;
+       int i;
+       rcti rect;
+
+       view3d_get_transformation(ar, rv3d, ob, &mats);
+       sculpt_get_redraw_rect(ar, rv3d,ob, &rect);
+
+#if 1
+       /* use some extra space just in case */
+       rect.xmin -= 2;
+       rect.xmax += 2;
+       rect.ymin -= 2;
+       rect.ymax += 2;
+#else
+       /* it was doing this before, allows to redraw a smaller
+          part of the screen but also gives artifaces .. */
+       rect.xmin += 2;
+       rect.xmax -= 2;
+       rect.ymin += 2;
+       rect.ymax -= 2;
+#endif
+
+       view3d_calculate_clipping(bb, planes, &mats, &rect);
+
+       for(i = 0; i < 16; ++i)
+               ((float*)planes)[i] = -((float*)planes)[i];
+
+       MEM_freeN(bb);
+
+       /* clear redraw flag from nodes */
+       BLI_pbvh_update(ob->sculpt->tree, PBVH_UpdateRedraw, NULL);
+}
+
+/************************** Undo *************************/
+
+typedef struct SculptUndoNode {
+       struct SculptUndoNode *next, *prev;
+
+       char idname[MAX_ID_NAME];       /* name instead of pointer*/
+       int maxvert;                            /* to verify if totvert it still the same */
+       void *node;                                     /* only during push, not valid afterwards! */
+
+       float (*co)[3];
+       int *index;
+       int totvert;
+} SculptUndoNode;
+
+static void update_cb(PBVHNode *node, void *data)
+{
+       BLI_pbvh_node_mark_update(node);
+}
+
+static void sculpt_undo_restore(bContext *C, ListBase *lb)
+{
+       Object *ob = CTX_data_active_object(C);
+       SculptSession *ss = ob->sculpt;
+       SculptUndoNode *unode;
+       MVert *mvert;
+       MultiresModifierData *mmd;
+       int *index;
+       int i, totvert, update= 0;
+
+       sculpt_update_mesh_elements(C, 0);
+
+       for(unode=lb->first; unode; unode=unode->next) {
+               if(!(strcmp(unode->idname, ob->id.name)==0))
+                       continue;
+               if(ss->totvert != unode->maxvert)
+                       continue;
+
+               index= unode->index;
+               totvert= unode->totvert;
+               mvert= ss->mvert;
+
+               for(i=0; i<totvert; i++) {
+                       float tmp[3];
+
+                       VECCOPY(tmp, mvert[index[i]].co);
+                       VECCOPY(mvert[index[i]].co, unode->co[i])
+                       VECCOPY(unode->co[i], tmp);
+
+                       mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+               }
+
+               update= 1;
+       }
+
+       if(update) {
+               /* we update all nodes still, should be more clever, but also
+                  needs to work correct when exiting/entering sculpt mode and
+                  the nodes get recreated, though in that case it could do all */
+               BLI_pbvh_search_callback(ss->tree, NULL, NULL, update_cb, NULL);
+               BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL);
+
+               /* not really convinced this is correct .. */
+               if((mmd=sculpt_multires_active(ob))) {
+                       mmd->undo_verts = ss->mvert;
+                       mmd->undo_verts_tot = ss->totvert;
+                       mmd->undo_signal = !!mmd->undo_verts;
+
+                       multires_force_update(ob);
+                       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+               }
+       }
+}
+
+static void sculpt_undo_free(ListBase *lb)
+{
+       SculptUndoNode *unode;
+
+       for(unode=lb->first; unode; unode=unode->next) {
+               if(unode->co)
+                       MEM_freeN(unode->co);
+               if(unode->index)
+                       MEM_freeN(unode->index);
+       }
+}
+
+static float (*sculpt_undo_push_node(SculptSession *ss, PBVHNode *node))[3]
+{
+       ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+       Object *ob= ss->ob;
+       SculptUndoNode *unode;
+       int i, totvert, *verts;
+
+       BLI_pbvh_node_get_verts(node, &verts, &totvert);
+
+       /* list is manipulated by multiple threads, so we lock */
+       BLI_lock_thread(LOCK_CUSTOM1);
+
+       for(unode=lb->first; unode; unode=unode->next) {
+               if(unode->node == node && strcmp(unode->idname, ob->id.name)==0) {
+                       BLI_unlock_thread(LOCK_CUSTOM1);
+                       return unode->co;
+               }
+       }
+
+       unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+       strcpy(unode->idname, ob->id.name);
+       unode->node= node;
+
+       unode->totvert= totvert;
+       unode->maxvert= ss->totvert;
+       /* we will use this while sculpting, is mapalloc slow to access then? */
+       unode->co= MEM_mapallocN(sizeof(float)*3*totvert, "SculptUndoNode.co");
+       unode->index= MEM_mapallocN(sizeof(int)*totvert, "SculptUndoNode.index");
+       undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(int))*totvert);
+       BLI_addtail(lb, unode);
+
+       BLI_unlock_thread(LOCK_CUSTOM1);
+
+       /* copy threaded, hopefully this is the performance critical part */
+       memcpy(unode->index, verts, sizeof(int)*totvert);
+       for(i=0; i<totvert; i++)
+               VECCOPY(unode->co[i], ss->mvert[verts[i]].co)
+       
+       return unode->co;
+}
+
+/************************ Looping Over Verts in a BVH Node *******************/
+
+typedef struct SculptVertexData {
+       float radius_squared;
+       float location[3];
+
+       MVert *mvert;
+       int *verts;
+       float (*origvert)[3];
+       int i, index, totvert;
+
+       float *co;
+       float *origco;
+       short *no;
+       float dist;
+} SculptVertexData;
+
+static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss,
+       PBVHNode *node, float (*origvert)[3], SculptVertexData *vd)
+{
+       vd->radius_squared= ss->cache->radius*ss->cache->radius;
+       VecCopyf(vd->location, ss->cache->location);
+
+       vd->mvert= ss->mvert;
+       vd->origvert= origvert;
+       vd->i= -1;
+       BLI_pbvh_node_get_verts(node, &vd->verts, &vd->totvert);
+}
+
+static int sculpt_node_verts_next(SculptVertexData *vd)
+{
+       vd->i++;
+
+       while(vd->i < vd->totvert) {
+               float delta[3], dsq;
+
+               vd->index= vd->verts[vd->i];
+               vd->co= vd->mvert[vd->index].co;
+               vd->origco= (vd->origvert)? vd->origvert[vd->i]: vd->co;
+               vd->no= vd->mvert[vd->index].no;
+               VECSUB(delta, vd->origco, vd->location);
+               dsq = INPR(delta, delta);
+
+               if(dsq < vd->radius_squared) {
+                       vd->dist = sqrt(dsq);
+                       return 1;
+               }
+
+               vd->i++;
+       }
+       
+       return 0;
+}
 
 /* ===== Sculpting =====
  *
@@ -236,6 +488,168 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache)
        }
 }
 
+/* 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. */
+               VecCopyf(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->mouse[0]) / bsize;
+                       float fy= (point_2d[1] - ss->cache->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,
+       float bb_min[3], float bb_max[3], void *data_v)
+{
+       SculptSearchSphereData *data = data_v;
+       float *center = data->ss->cache->location, nearest[3];
+       float t[3];
+       int i;
+
+       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]; 
+       }
+       
+       VecSubf(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])
 {
@@ -265,26 +679,41 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons
        }
 }
 
-/* Currently only for the draw brush; finds average normal for all active
-   vertices */
-static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const ListBase* active_verts)
+/* For draw/layer/flatten; finds average normal for all active vertices */
+static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode)
 {
        Brush *brush = paint_brush(&sd->paint);
        StrokeCache *cache = ss->cache;
-       ActiveData *node = active_verts->first;
        const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
-       float out_flip[3];
-       float *out_dir = cache->view_normal_symmetry;
-       
-       out[0]=out[1]=out[2] = out_flip[0]=out_flip[1]=out_flip[2] = 0;
+       float out[3] = {0.0f, 0.0f, 0.0f};
+       float out_flip[3] = {0.0f, 0.0f, 0.0f};
+       float out_dir[3];
+       int n;
+
+       VecCopyf(out_dir, cache->view_normal_symmetry);
+
+       /* threaded loop over nodes */
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               float nout[3] = {0.0f, 0.0f, 0.0f};
+               float nout_flip[3] = {0.0f, 0.0f, 0.0f};
+               
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
 
-       if(brush->flag & BRUSH_ANCHORED) {
-               for(; node; node = node->next)
-                       add_norm_if(out_dir, out, out_flip, cache->orig_norms[node->Index]);
-       }
-       else {
-               for(; node; node = node->next)
-                       add_norm_if(out_dir, out, out_flip, ss->mvert[node->Index].no);
+               if(brush->flag & BRUSH_ANCHORED) {
+                       while(sculpt_node_verts_next(&vd))
+                               add_norm_if(out_dir, nout, nout_flip, cache->orig_norms[vd.index]);
+               }
+               else {
+                       while(sculpt_node_verts_next(&vd))
+                               add_norm_if(out_dir, nout, nout_flip, ss->mvert[vd.index].no);
+               }
+
+               /* we sum per node and add together later for threads */
+               #pragma omp critical
+               VecAddf(out, out, nout);
+               VecAddf(out_flip, out_flip, nout_flip);
        }
 
        if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
@@ -293,46 +722,50 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const
        
        Normalize(out);
 
-       if(out_dir) {
-               out[0] = out_dir[0] * view + out[0] * (10-view);
-               out[1] = out_dir[1] * view + out[1] * (10-view);
-               out[2] = out_dir[2] * view + out[2] * (10-view);
-       }
+       out[0] = out_dir[0] * view + out[0] * (10-view);
+       out[1] = out_dir[1] * view + out[1] * (10-view);
+       out[2] = out_dir[2] * view + out[2] * (10-view);
        
        Normalize(out);
+       VecCopyf(area_normal, out);
 }
 
-static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_verts)
+static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
 {
-       float area_normal[3];
-       ActiveData *node= active_verts->first;
-       float* buffer;
-
-       calc_area_normal(sd, ss, area_normal, active_verts);
-       
-       buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
-       while(node){
-               float *co= ss->mvert[node->Index].co;
-
-               const float val[3]= {co[0]+area_normal[0]*ss->cache->radius*node->Fade*ss->cache->scale[0],
-                                    co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1],
-                                    co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]};
-
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[node->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               sculpt_clip(sd, ss, &buffer[cur->element*3], val);
-                               cur = cur->next;
-                       }
+       Brush *brush = paint_brush(&sd->paint);
+       float offset[3], area_normal[3];
+       float bstrength= ss->cache->bstrength;
+       int n;
+
+       /* area normal */
+       calc_area_normal(sd, ss, area_normal, nodes, totnode);
+
+       /* offset with as much as possible factored in already */
+       offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength;
+       offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength;
+       offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength;
+
+       /* threaded loop over nodes */
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               
+               sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       /* offset vertex */
+                       const float fade = tex_strength(ss, brush, vd.co, vd.dist);
+                       const float val[3]= {vd.co[0] + offset[0]*fade,
+                                                                vd.co[1] + offset[1]*fade,
+                                                                vd.co[2] + offset[2]*fade};
+
+                       sculpt_clip(sd, ss, vd.co, val);
+                       ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                }
 
-               sculpt_clip(sd, ss, co, val);
-
-               node= node->next;
+               BLI_pbvh_node_mark_update(nodes[n]);
        }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 /* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -379,527 +812,378 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
                VecCopyf(avg, ss->mvert[vert].co);
 }
 
-static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
+static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
 {
-       ActiveData *node= active_verts->first;
-       float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-       int i;
-       
-       for(i = 0; i < 2; ++i) {
-               while(node){
-                       float *co= ss->mvert[node->Index].co;
-                       float avg[3], val[3];
-                       
-                       neighbor_average(ss, avg, node->Index);
-                       val[0] = co[0]+(avg[0]-co[0])*node->Fade;
-                       val[1] = co[1]+(avg[1]-co[1])*node->Fade;
-                       val[2] = co[2]+(avg[2]-co[2])*node->Fade;
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       int iteration, n;
+
+       for(iteration = 0; iteration < 2; ++iteration) {
+               #pragma omp parallel for private(n) schedule(static)
+               for(n=0; n<totnode; n++) {
+                       SculptVertexData vd;
                        
-                       sculpt_clip(s, ss, co, val);                    
-                       if( buffer != 0 ) {                             
-                               IndexLink *cur = &ss->drawobject->indices[node->Index]; 
-                               while( cur != 0 && cur->element != -1 ) {
-                                       sculpt_clip(s, ss, &buffer[cur->element*3], val);
-                                       cur = cur->next;
-                               }
+                       sculpt_undo_push_node(ss, nodes[n]);
+                       sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+                       while(sculpt_node_verts_next(&vd)) {
+                               const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+                               float avg[3], val[3];
+                               
+                               neighbor_average(ss, avg, vd.index);
+                               val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade;
+                               val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade;
+                               val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade;
+                               
+                               sculpt_clip(sd, ss, vd.co, val);                        
+                               ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                        }
-                       node= node->next;
-               }
-       }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
-}
-
-static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
-{
-       ActiveData *node= active_verts->first;
-       float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
 
-       while(node) {
-               float *co= ss->mvert[node->Index].co;
-               const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade,
-                                    co[1]+(ss->cache->location[1]-co[1])*node->Fade,
-                                    co[2]+(ss->cache->location[2]-co[2])*node->Fade};
-
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[node->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               sculpt_clip(s, ss, &buffer[cur->element*3], val);
-                               cur = cur->next;
-                       }
+                       BLI_pbvh_node_mark_update(nodes[n]);
                }
-
-               sculpt_clip(s, ss, co, val);
-               node= node->next;
        }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
-static void do_grab_brush(Sculpt *sd, SculptSession *ss)
+static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
 {
-       ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first;
-       float add[3];
-       float grab_delta[3];
-       float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-       
-       VecCopyf(grab_delta, ss->cache->grab_delta_symmetry);
-       
-       while(node) {
-               float *co= ss->mvert[node->Index].co;
-               
-               VecCopyf(add, grab_delta);
-               VecMulf(add, node->Fade);
-               VecAddf(add, add, co);
-
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[node->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               sculpt_clip(sd, ss, &buffer[cur->element*3], add);
-                               cur = cur->next;
-                       }
-               }
-
-               sculpt_clip(sd, ss, co, add);
-
-               node= node->next;
-       }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
-       
-}
-
-static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts)
-{
-       float area_normal[3];
-       ActiveData *node= active_verts->first;
-       float *buffer;
-       float lim= ss->cache->radius / 4;
-
-       if(ss->cache->flip)
-               lim = -lim;
-
-       calc_area_normal(sd, ss, area_normal, active_verts);
-
-       buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-       while(node){
-               float *disp= &ss->layer_disps[node->Index];
-               float *co= ss->mvert[node->Index].co;
-               float val[3];
-               
-               *disp+= node->Fade;
-               
-               /* Don't let the displacement go past the limit */
-               if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
-                       *disp = lim;
-               
-               val[0] = ss->mesh_co_orig[node->Index][0]+area_normal[0] * *disp*ss->cache->scale[0];
-               val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
-               val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
-
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[node->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               sculpt_clip(sd, ss, &buffer[cur->element*3], val);
-                               cur = cur->next;
-                       }
-               }
-
-               sculpt_clip(sd, ss, co, val);
-
-               node= node->next;
-       }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
-}
-
-static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
-{
-       ActiveData *node= active_verts->first;
-       float add[3];
-       float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
-
-       while(node) {
-               float *co= ss->mvert[node->Index].co;
-               short *no= ss->mvert[node->Index].no;
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       int n;
 
-               add[0]= no[0]/ 32767.0f;
-               add[1]= no[1]/ 32767.0f;
-               add[2]= no[2]/ 32767.0f;
-               VecMulf(add, node->Fade * ss->cache->radius);
-               add[0]*= ss->cache->scale[0];
-               add[1]*= ss->cache->scale[1];
-               add[2]*= ss->cache->scale[2];
-               VecAddf(add, add, co);
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
                
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[node->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               sculpt_clip(s, ss, &buffer[cur->element*3], add);
-                               cur = cur->next;
-                       }
+               sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+                       const float val[3]= {vd.co[0]+(vd.location[0]-vd.co[0])*fade,
+                                                                vd.co[1]+(vd.location[1]-vd.co[1])*fade,
+                                                                vd.co[2]+(vd.location[2]-vd.co[2])*fade};
+                       
+                       sculpt_clip(sd, ss, vd.co, val);                        
+                       ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                }
 
-               sculpt_clip(s, ss, co, add);
-
-               node= node->next;
+               BLI_pbvh_node_mark_update(nodes[n]);
        }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
-static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3])
+static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
 {
-       ActiveData *outer[FLATTEN_SAMPLE_SIZE];
-       int i;
-       
-       for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
-               outer[i] = node;
-               
-       for(; node; node = node->next) {
-               for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
-                       if(node->dist > outer[i]->dist) {
-                               outer[i] = node;
-                               break;
-                       }
-               }
-       }
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       float grab_delta[3], (*origco)[3];
+       int n;
        
-       co[0] = co[1] = co[2] = 0.0f;
-       for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
-               VecAddf(co, co, ss->mvert[outer[i]->Index].co);
-       VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
-}
-
-/* Projects a point onto a plane along the plane's normal */
-static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
-{
-       float p1[3], sub1[3], sub2[3];
-
-       /* Find the intersection between squash-plane and vertex (along the area normal) */
-       VecSubf(p1, co, plane_normal);
-       VecSubf(sub1, plane_center, p1);
-       VecSubf(sub2, co, p1);
-       VecSubf(intr, co, p1);
-       VecMulf(intr, Inpf(plane_normal, sub1) / Inpf(plane_normal, sub2));
-       VecAddf(intr, intr, p1);
-}
-
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip)
-{
-       float delta[3];
-       float d;
-
-       VecSubf(delta, co, plane_center);
-       d = Inpf(plane_normal, delta);
-
-       if(flip)
-               d = -d;
-
-       return d <= 0.0f;
-}
-
-static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase *active_verts, int clay)
-{
-       ActiveData *node= active_verts->first;
-       /* area_normal and cntr define the plane towards which vertices are squashed */
-       float area_normal[3];
-       float cntr[3], cntr2[3], bstr = 0;
-       int flip = 0;
-       float *buffer;
-       calc_area_normal(sd, ss, area_normal, active_verts);
-       calc_flatten_center(ss, node, cntr);
-
-       if(clay) {
-               bstr= brush_strength(sd, ss->cache);
-               /* Limit clay application to here */
-               cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0];
-               cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1];
-               cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
-               flip = bstr < 0;
-       }
-
-       buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0;
+       VecCopyf(grab_delta, ss->cache->grab_delta_symmetry);
 
-       while(node){
-               float *co= ss->mvert[node->Index].co;
-               float intr[3], val[3];
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
                
-               if(!clay || plane_point_side(co, area_normal, cntr2, flip)) {
-                       /* Find the intersection between squash-plane and vertex (along the area normal) */             
-                       point_plane_project(intr, co, area_normal, cntr);
-
-                       VecSubf(val, intr, co);
-
-                       if(clay) {
-                               if(bstr > FLT_EPSILON)
-                                       VecMulf(val, node->Fade / bstr);
-                               else
-                                       VecMulf(val, node->Fade);
-                               /* Clay displacement */
-                               val[0]+=area_normal[0] * ss->cache->scale[0]*node->Fade;
-                               val[1]+=area_normal[1] * ss->cache->scale[1]*node->Fade;
-                               val[2]+=area_normal[2] * ss->cache->scale[2]*node->Fade;
-                       }
-                       else
-                               VecMulf(val, fabs(node->Fade));
+               origco= sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], origco, &vd);
 
-                       VecAddf(val, val, co);
-
-                       if( buffer != 0 ) {
-                               IndexLink *cur = &ss->drawobject->indices[node->Index];
-                               while( cur != 0 && cur->element != -1 ) {
-                                       sculpt_clip(sd, ss, &buffer[cur->element*3], val);
-                                       cur = cur->next;
-                               }
-                       }                       
-                       sculpt_clip(sd, ss, co, val);
+               while(sculpt_node_verts_next(&vd)) {
+                       const float fade = tex_strength(ss, brush, origco[vd.i], vd.dist)*bstrength;
+                       const float add[3]= {vd.co[0]+fade*grab_delta[0],
+                                                                vd.co[1]+fade*grab_delta[1],
+                                                                vd.co[2]+fade*grab_delta[2]};
 
+                       sculpt_clip(sd, ss, vd.co, add);                        
+                       ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                }
-               
-               node= node->next;
-       }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->vertices );
-}
 
-/* 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;
+               BLI_pbvh_node_mark_update(nodes[n]);
+       }
 }
 
-/* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len)
+static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
 {
-       Brush *br = paint_brush(&sd->paint);
-       MTex *tex = NULL;
-       float avg= 1;
-
-       if(br->texact >= 0)
-               tex = br->mtex[br->texact];
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       float area_normal[3], offset[3];
+       float lim= ss->cache->radius / 4;
+       int n;
 
-       if(!tex) {
-               avg= 1;
-       }
-       else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
-               float jnk;
+       if(ss->cache->flip)
+               lim = -lim;
 
-               /* 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];
+       calc_area_normal(sd, ss, area_normal, nodes, totnode);
 
-               /* 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. */
-               VecCopyf(flip, point);
-               flip_coord(flip, flip, ss->cache->symmetry);
-               projectf(ss->cache->mats, flip, point_2d);
+       offset[0]= ss->cache->scale[0]*area_normal[0];
+       offset[1]= ss->cache->scale[1]*area_normal[1];
+       offset[2]= ss->cache->scale[2]*area_normal[2];
 
-               /* 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];
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               float (*origco)[3];
+               
+               origco= sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+                       float *disp= &ss->layer_disps[vd.index];
+                       float val[3];
                        
-                       float fx= point_2d[0];
-                       float fy= point_2d[1];
+                       *disp+= fade;
                        
-                       float angle= atan2(fy, fx) - rot;
-                       float flen= sqrtf(fx*fx + fy*fy);
+                       /* Don't let the displacement go past the limit */
+                       if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
+                               *disp = lim;
                        
-                       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(ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+                               /* persistent base */
+                               val[0] = ss->layer_co[vd.index][0] + (*disp)*offset[0];
+                               val[1] = ss->layer_co[vd.index][1] + (*disp)*offset[1];
+                               val[2] = ss->layer_co[vd.index][2] + (*disp)*offset[2];
                        }
-                       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 {
+                               val[0] = origco[vd.i][0] + (*disp)*offset[0];
+                               val[1] = origco[vd.i][1] + (*disp)*offset[1];
+                               val[2] = origco[vd.i][2] + (*disp)*offset[2];
+                       }
+
+                       sculpt_clip(sd, ss, vd.co, val);
+                       ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                }
-               else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
-                       float fx= (point_2d[0] - ss->cache->mouse[0]) / bsize;
-                       float fy= (point_2d[1] - ss->cache->mouse[1]) / bsize;
 
-                       float angle= atan2(fy, fx) - rot;
-                       float flen= sqrtf(fx*fx + fy*fy);
+               BLI_pbvh_node_mark_update(nodes[n]);
+       }
+}
+
+static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       int n;
+
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               
+               sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+                       float add[3];
                        
-                       fx = flen * cos(angle) + 0.5;
-                       fy = flen * sin(angle) + 0.5;
+                       add[0]= vd.no[0]/32767.0f;
+                       add[1]= vd.no[1]/32767.0f;
+                       add[2]= vd.no[2]/32767.0f;
+                       VecMulf(add, fade * ss->cache->radius);
+                       add[0]*= ss->cache->scale[0];
+                       add[1]*= ss->cache->scale[1];
+                       add[2]*= ss->cache->scale[2];
+                       VecAddf(add, add, vd.co);
+                       
+                       sculpt_clip(sd, ss, vd.co, add);
+                       ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
+               }
 
-                       avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
+               BLI_pbvh_node_mark_update(nodes[n]);
+       }
+}
+
+static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3])
+{
+       float outer_dist[FLATTEN_SAMPLE_SIZE];
+       int outer_index[FLATTEN_SAMPLE_SIZE];
+       int i, n;
+       
+       for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+               outer_index[i] = 0;
+               outer_dist[i]= -1.0f;
+       }
+               
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+                               if(vd.dist > outer_dist[i]) {
+                                       outer_index[i] = vd.index;
+                                       break;
+                               }
+                       }
                }
+
+               BLI_pbvh_node_mark_update(nodes[n]);
        }
+       
+       co[0] = co[1] = co[2] = 0.0f;
+       for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
+               VecAddf(co, co, ss->mvert[outer_index[i]].co);
+       VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
+}
 
-       avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
+/* Projects a point onto a plane along the plane's normal */
+static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
+{
+       float p1[3], sub1[3], sub2[3];
 
-       return avg;
+       /* Find the intersection between squash-plane and vertex (along the area normal) */
+       VecSubf(p1, co, plane_normal);
+       VecSubf(sub1, plane_center, p1);
+       VecSubf(sub2, co, p1);
+       VecSubf(intr, co, p1);
+       VecMulf(intr, Inpf(plane_normal, sub1) / Inpf(plane_normal, sub2));
+       VecAddf(intr, intr, p1);
+}
+
+static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip)
+{
+       float delta[3];
+       float d;
+
+       VecSubf(delta, co, plane_center);
+       d = Inpf(plane_normal, delta);
+
+       if(flip)
+               d = -d;
+
+       return d <= 0.0f;
 }
 
-/* Mark area around the brush as damaged. projverts are marked if they are
-   inside the area and the damaged rectangle in 2D screen coordinates is 
-   added to damaged_rects. */
-static void sculpt_add_damaged_rect(SculptSession *ss)
+static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay)
 {
-       short p[2];
-       RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
-       const float radius = MAX2(ss->cache->pixel_radius, ss->cache->previous_pixel_radius);
-       unsigned i;
+       /* area_normal and cntr define the plane towards which vertices are squashed */
+       Brush *brush = paint_brush(&sd->paint);
+       float bstrength= ss->cache->bstrength;
+       float area_normal[3];
+       float cntr[3], cntr2[3], bstr = 0;
+       int n, flip = 0;
+
+       calc_area_normal(sd, ss, area_normal, nodes, totnode);
+       calc_flatten_center(sd, ss, nodes, totnode, cntr);
+
+       if(clay) {
+               bstr= brush_strength(sd, ss->cache);
+               /* Limit clay application to here */
+               cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0];
+               cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1];
+               cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
+               flip = bstr < 0;
+       }
+
+       #pragma omp parallel for private(n) schedule(static)
+       for(n=0; n<totnode; n++) {
+               SculptVertexData vd;
+               
+               sculpt_undo_push_node(ss, nodes[n]);
+               sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd);
+
+               while(sculpt_node_verts_next(&vd)) {
+                       float intr[3], val[3];
+                       
+                       if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) {
+                               const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength;
+
+                               /* Find the intersection between squash-plane and vertex (along the area normal) */             
+                               point_plane_project(intr, vd.co, area_normal, cntr);
 
-       /* Find center */
-       project(ss->cache->mats, ss->cache->location, p);
-       rn->r.xmin= p[0] - radius;
-       rn->r.ymin= p[1] - radius;
-       rn->r.xmax= p[0] + radius;
-       rn->r.ymax= p[1] + radius;
+                               VecSubf(val, intr, vd.co);
 
-       BLI_addtail(&ss->damaged_rects, rn);
+                               if(clay) {
+                                       if(bstr > FLT_EPSILON)
+                                               VecMulf(val, fade / bstr);
+                                       else
+                                               VecMulf(val, fade);
+                                       /* Clay displacement */
+                                       val[0]+=area_normal[0] * ss->cache->scale[0]*fade;
+                                       val[1]+=area_normal[1] * ss->cache->scale[1]*fade;
+                                       val[2]+=area_normal[2] * ss->cache->scale[2]*fade;
+                               }
+                               else
+                                       VecMulf(val, fabs(fade));
+
+                               VecAddf(val, val, vd.co);
 
-       /* Update insides */
-       for(i=0; i<ss->totvert; ++i) {
-               if(!ss->projverts[i].inside) {
-                       if(ss->projverts[i].co[0] > rn->r.xmin && ss->projverts[i].co[1] > rn->r.ymin &&
-                          ss->projverts[i].co[0] < rn->r.xmax && ss->projverts[i].co[1] < rn->r.ymax) {
-                               ss->projverts[i].inside= 1;
+                               sculpt_clip(sd, ss, vd.co, val);
+                               ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE;
                        }
                }
-               // XXX: remember to fix this!
-               // temporary pass
-               ss->projverts[i].inside = 1;
+
+               BLI_pbvh_node_mark_update(nodes[n]);
        }
 }
 
 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;
-       Mesh *me= NULL; /*XXX: get_mesh(OBACT); */
-       const float bstrength= brush_strength(sd, cache);
-       KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */
-       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= VecLenf(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;
+                       VecCopyf(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];
+                       VecCopyf(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;
@@ -919,9 +1203,13 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
                        BLI_freelistN(&active_verts);
                else {
                        if(b->sculpt_tool != SCULPT_TOOL_GRAB)
-                               addlisttolist(&ss->damaged_verts, &active_verts);
+                               addlisttolist(&ss->modified_verts, &active_verts);
                }
-       }
+#endif
+               
+               if((brush->sculpt_tool != SCULPT_TOOL_GRAB) && nodes)
+                       MEM_freeN(nodes);
+       }       
 }
 
 /* Flip all the editdata across the axis/axes specified by symm. Used to
@@ -943,6 +1231,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
        VecCopyf(cache->location, cache->true_location);
        VecCopyf(cache->grab_delta_symmetry, cache->grab_delta);
        cache->symmetry = 0;
+       cache->bstrength = brush_strength(sd, cache);
        do_brush_action(sd, ss, cache);
 
        for(i = 1; i <= symm; ++i) {
@@ -955,110 +1244,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
        cache->first_time = 0;
 }
 
-static void add_face_normal(vec3f *norm, MVert *mvert, const MFace* face, float *fn)
-{
-       vec3f c= {mvert[face->v1].co[0],mvert[face->v1].co[1],mvert[face->v1].co[2]};
-       vec3f b= {mvert[face->v2].co[0],mvert[face->v2].co[1],mvert[face->v2].co[2]};
-       vec3f a= {mvert[face->v3].co[0],mvert[face->v3].co[1],mvert[face->v3].co[2]};
-       vec3f s1, s2;
-       float final[3];
-
-       VecSubf(&s1.x,&a.x,&b.x);
-       VecSubf(&s2.x,&c.x,&b.x);
-
-       final[0] = s1.y * s2.z - s1.z * s2.y;
-       final[1] = s1.z * s2.x - s1.x * s2.z;
-       final[2] = s1.x * s2.y - s1.y * s2.x;
-
-       if(fn)
-               VecCopyf(fn, final);
-
-       norm->x+= final[0];
-       norm->y+= final[1];
-       norm->z+= final[2];
-}
-
-static void update_damaged_vert(SculptSession *ss, ListBase *lb)
-{
-       ActiveData *vert;
-    
-       float *buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->normals ):0;
-       for(vert= lb->first; vert; vert= vert->next) {
-               vec3f norm= {0,0,0};            
-               IndexNode *face= ss->fmap[vert->Index].first;
-
-               while(face){
-                       float *fn = NULL;
-                       if(ss->face_normals)
-                               fn = &ss->face_normals[face->index*3];
-                       add_face_normal(&norm, ss->mvert, &ss->mface[face->index], fn);
-                       face= face->next;
-               }
-               Normalize(&norm.x);
-               
-               ss->mvert[vert->Index].no[0]=norm.x*32767;
-               ss->mvert[vert->Index].no[1]=norm.y*32767;
-               ss->mvert[vert->Index].no[2]=norm.z*32767;
-
-               if( buffer != 0 ) {
-                       IndexLink *cur = &ss->drawobject->indices[vert->Index];
-                       while( cur != 0 && cur->element != -1 ) {
-                               int i = ss->drawobject->faceRemap[cur->element/3];
-                               if( ss->mface[i].flag & ME_SMOOTH ) {
-                                       VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
-                               }
-                               else {
-                                       float norm[3];
-                                       if( ss->mface[i].v4 )
-                                               CalcNormFloat4(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, ss->mvert[ss->mface[i].v4].co, norm);
-                                       else
-                                               CalcNormFloat(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, norm);
-                                       VECCOPY(&buffer[(cur->element-cur->element%3)*3],norm);
-                                       VECCOPY(&buffer[(cur->element-cur->element%3+1)*3],norm);
-                                       VECCOPY(&buffer[(cur->element-cur->element%3+2)*3],norm);
-
-                                       /* maybe this was a quad - need to update the other triangle of the quad */
-                                       if( ss->drawobject->faceRemap[cur->element/3-1] == i ) {
-                                               VECCOPY(&buffer[(cur->element-cur->element%3-3)*3],norm);
-                                               VECCOPY(&buffer[(cur->element-cur->element%3-2)*3],norm);
-                                               VECCOPY(&buffer[(cur->element-cur->element%3-1)*3],norm);
-                                       }
-                                       if( ss->drawobject->faceRemap[cur->element/3+1] == i ) {
-                                               VECCOPY(&buffer[(cur->element-cur->element%3+3)*3],norm);
-                                               VECCOPY(&buffer[(cur->element-cur->element%3+4)*3],norm);
-                                               VECCOPY(&buffer[(cur->element-cur->element%3+5)*3],norm);
-                                       }
-                               }
-
-                               //VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
-                               cur = cur->next;
-                       }
-               }
-       }
-       if( buffer != 0 )
-               GPU_buffer_unlock( ss->drawobject->normals );
-}
-
-static void calc_damaged_verts(SculptSession *ss)
-{
-       int i;
-       
-       for(i=0; i<8; ++i)
-               update_damaged_vert(ss, &ss->cache->grab_active_verts[i]);
-       update_damaged_vert(ss, &ss->damaged_verts);
-       BLI_freelistN(&ss->damaged_verts);
-       ss->damaged_verts.first = ss->damaged_verts.last = NULL;
-}
-
-#if 0
-static void projverts_clear_inside(SculptSession *ss)
-{
-       int i;
-       for(i = 0; i < ss->totvert; ++i)
-               ss->projverts[i].inside = 0;
-}
-#endif
-
 static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
 {
        Brush *brush = paint_brush(&sd->paint);
@@ -1076,20 +1261,6 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
        }
 }
 
-static void sculptmode_update_all_projverts(SculptSession *ss)
-{
-       unsigned i;
-
-       if(!ss->projverts)
-               ss->projverts = MEM_mallocN(sizeof(ProjVert)*ss->totvert,"ProjVerts");
-
-       for(i=0; i<ss->totvert; ++i) {
-               project(ss->cache->mats, ss->vertexcosnos ? &ss->vertexcosnos[i * 6] : ss->mvert[i].co,
-                       ss->projverts[i].co);
-               ss->projverts[i].inside= 0;
-       }
-}
-
 /* Checks whether full update mode (slower) needs to be used to work with modifiers */
 char sculpt_modifiers_active(Object *ob)
 {
@@ -1105,7 +1276,7 @@ char sculpt_modifiers_active(Object *ob)
 
 /* Sculpt mode handles multires differently from regular meshes, but only if
    it's the last modifier on the stack and it is not on the first level */
-static struct MultiresModifierData *sculpt_multires_active(Object *ob)
+struct MultiresModifierData *sculpt_multires_active(Object *ob)
 {
        ModifierData *md, *nmd;
        
@@ -1127,15 +1298,15 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
        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,
+                                      CTX_wm_view3d(C)->customdata_mask);
        SculptSession *ss = ob->sculpt;
-       int oldtotvert = ss->totvert;
-       DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
-
+       
        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);
@@ -1150,22 +1321,10 @@ static void sculpt_update_mesh_elements(bContext *C)
                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(dm);
+       ss->fmap = (need_fmap)? dm->getFaceMap(dm): NULL;
 }
 
 static int sculpt_mode_poll(bContext *C)
@@ -1179,27 +1338,27 @@ int sculpt_poll(bContext *C)
        return sculpt_mode_poll(C) && paint_poll(C);
 }
 
-static void sculpt_undo_push(bContext *C, Sculpt *sd)
+static char *sculpt_tool_name(Sculpt *sd)
 {
        Brush *brush = paint_brush(&sd->paint);
 
        switch(brush->sculpt_tool) {
        case SCULPT_TOOL_DRAW:
-               ED_undo_push(C, "Draw Brush"); break;
+               return "Draw Brush"; break;
        case SCULPT_TOOL_SMOOTH:
-               ED_undo_push(C, "Smooth Brush"); break;
+               return "Smooth Brush"; break;
        case SCULPT_TOOL_PINCH:
-               ED_undo_push(C, "Pinch Brush"); break;
+               return "Pinch Brush"; break;
        case SCULPT_TOOL_INFLATE:
-               ED_undo_push(C, "Inflate Brush"); break;
+               return "Inflate Brush"; break;
        case SCULPT_TOOL_GRAB:
-               ED_undo_push(C, "Grab Brush"); break;
+               return "Grab Brush"; break;
        case SCULPT_TOOL_LAYER:
-               ED_undo_push(C, "Layer Brush"); break;
+               return "Layer Brush"; break;
        case SCULPT_TOOL_FLATTEN:
-               ED_undo_push(C, "Flatten Brush"); break;
+               return "Flatten Brush"; break;
        default:
-               ED_undo_push(C, "Sculpting"); break;
+               return "Sculpting"; break;
        }
 }
 
@@ -1251,15 +1410,13 @@ static void SCULPT_OT_radial_control(wmOperatorType *ot)
 /**** Operator for applying a stroke (various attributes including mouse path)
       using the current brush. ****/
 
-static float unproject_brush_radius(SculptSession *ss, float offset)
+static float unproject_brush_radius(ViewContext *vc, float center[3], float offset)
 {
-       float brush_edge[3];
-
-       /* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */
-       view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
-                 ss->cache->initial_mouse[1], ss->cache->depth);
+       float delta[3];
 
-       return VecLenf(ss->cache->true_location, brush_edge);
+       initgrabz(vc->rv3d, center[0], center[1], center[2]);
+       window_to_3d_delta(vc->ar, delta, offset, 0);
+               return VecLength(delta);
 }
 
 static void sculpt_cache_free(StrokeCache *cache)
@@ -1271,8 +1428,10 @@ static void sculpt_cache_free(StrokeCache *cache)
                MEM_freeN(cache->face_norms);
        if(cache->mats)
                MEM_freeN(cache->mats);
-       for(i = 0; i < 8; ++i) 
-               BLI_freelistN(&cache->grab_active_verts[i]);
+       for(i = 0; i < 8; ++i) {
+               if(cache->grab_active_nodes[i])
+                       MEM_freeN(cache->grab_active_nodes[i]);
+       }
        MEM_freeN(cache);
 }
 
@@ -1290,62 +1449,57 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
        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];
 
        /* Truly temporary data that isn't stored in properties */
 
-       cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
-       view3d_get_transformation(vc, vc->obact, cache->mats);
-
-       sculpt_update_mesh_elements(C);
-
-       /* Initialize layer brush displacements */
-       if(brush->sculpt_tool == SCULPT_TOOL_LAYER &&
-          (!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT))) {
-               if(ss->layer_disps)
-                       MEM_freeN(ss->layer_disps);
-               ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements");
-       }
+       cache->vc = vc;
+       cache->brush = brush;
 
-       /* Make copies of the mesh vertex locations and normals for some tools */
-       if(brush->sculpt_tool == SCULPT_TOOL_LAYER || (brush->flag & BRUSH_ANCHORED)) {
-               if(brush->sculpt_tool != SCULPT_TOOL_LAYER ||
-                  !ss->mesh_co_orig || !(brush->flag & BRUSH_PERSISTENT)) {
-                       if(!ss->mesh_co_orig)
-                               ss->mesh_co_orig= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
+       cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
+       view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
+
+       /* Initialize layer brush displacements and persistent coords */
+       if(brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+               if(!ss->layer_disps || !(brush->flag & BRUSH_PERSISTENT)) {
+                       if(ss->layer_disps)
+                               MEM_freeN(ss->layer_disps);
+                       ss->layer_disps = MEM_callocN(sizeof(float) * ss->totvert, "layer brush displacements");
+               }
+               if(!ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+                       if(!ss->layer_co)
+                               ss->layer_co= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
                                                                       "sculpt mesh vertices copy");
                        for(i = 0; i < ss->totvert; ++i)
-                               VecCopyf(ss->mesh_co_orig[i], ss->mvert[i].co);
+                               VecCopyf(ss->layer_co[i], ss->mvert[i].co);
                }
+       }
 
-               if(brush->flag & BRUSH_ANCHORED) {
-                       cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm");
-                       for(i = 0; i < ss->totvert; ++i) {
-                               cache->orig_norms[i][0] = ss->mvert[i].no[0];
-                               cache->orig_norms[i][1] = ss->mvert[i].no[1];
-                               cache->orig_norms[i][2] = ss->mvert[i].no[2];
-                       }
+       /* Make copies of the mesh vertex locations and normals for some tools */
+       if(brush->flag & BRUSH_ANCHORED) {
+               cache->orig_norms= MEM_mallocN(sizeof(short) * 3 * ss->totvert, "Sculpt orig norm");
+               for(i = 0; i < ss->totvert; ++i) {
+                       cache->orig_norms[i][0] = ss->mvert[i].no[0];
+                       cache->orig_norms[i][1] = ss->mvert[i].no[1];
+                       cache->orig_norms[i][2] = ss->mvert[i].no[2];
+               }
 
-                       if(ss->face_normals) {
-                               float *fn = ss->face_normals;
-                               cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
-                               for(i = 0; i < ss->totface; ++i, fn += 3)
-                                       VecCopyf(cache->face_norms[i], fn);
-                       }
+               if(ss->face_normals) {
+                       float *fn = ss->face_normals;
+                       cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms");
+                       for(i = 0; i < ss->totface; ++i, fn += 3)
+                               VecCopyf(cache->face_norms[i], fn);
                }
        }
 
-       view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
-       cache->initial_radius = unproject_brush_radius(ss, brush->size);
        cache->rotation = 0;
        cache->first_time = 1;
 }
 
 /* Initialize the stroke cache variants from operator properties */
-static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerRNA *ptr)
+static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
 {
        StrokeCache *cache = ss->cache;
        Brush *brush = paint_brush(&sd->paint);
@@ -1353,7 +1507,7 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
        
        int dx, dy;
 
-       if(!(brush->flag & BRUSH_ANCHORED))
+       if(!(brush->flag & BRUSH_ANCHORED) || cache->first_time)
                RNA_float_get_array(ptr, "location", cache->true_location);
        cache->flip = RNA_boolean_get(ptr, "flip");
        RNA_float_get_array(ptr, "mouse", cache->mouse);
@@ -1364,6 +1518,9 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
        cache->previous_pixel_radius = cache->pixel_radius;
        cache->pixel_radius = brush->size;
 
+       if(cache->first_time)
+               cache->initial_radius = unproject_brush_radius(cache->vc, cache->true_location, brush->size);
+
        if(brush->flag & BRUSH_SIZE_PRESSURE) {
                cache->pixel_radius *= cache->pressure;
                cache->radius = cache->initial_radius * cache->pressure;
@@ -1375,7 +1532,8 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
                dx = cache->mouse[0] - cache->initial_mouse[0];
                dy = cache->mouse[1] - cache->initial_mouse[1];
                cache->pixel_radius = sqrt(dx*dx + dy*dy);
-               cache->radius = unproject_brush_radius(ss, cache->pixel_radius);
+               cache->radius = unproject_brush_radius(paint_stroke_view_context(stroke),
+                                                      cache->true_location, cache->pixel_radius);
                cache->rotation = atan2(dy, dx);
        }
        else if(brush->flag & BRUSH_RAKE) {
@@ -1398,17 +1556,106 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
 
        /* Find the grab delta */
        if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
-               view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+               // XXX: view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+               initgrabz(cache->vc->rv3d, cache->true_location[0], cache->true_location[1], cache->true_location[2]);
+               window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
                if(!cache->first_time)
                        VecSubf(cache->grab_delta, grab_location, cache->old_grab_location);
                VecCopyf(cache->old_grab_location, grab_location);
        }
 }
 
+/* XXX: Code largely copied from bvhutils.c, should be unified */
+/* Returns 1 if a better intersection has been found */
+static int ray_face_intersection(float ray_start[3], float ray_normal[3],
+                                float *t0, float *t1, float *t2, float *t3,
+                                float *fdist)
+{
+       int hit = 0;
+
+       do
+       {       
+               float dist = FLT_MAX;
+                       
+               if(!RayIntersectsTriangle(ray_start, ray_normal, t0, t1, t2,
+                                        &dist, NULL))
+                       dist = FLT_MAX;
+
+               if(dist >= 0 && dist < *fdist) {
+                       hit = 1;
+                       *fdist = dist;
+               }
+
+               t1 = t2;
+               t2 = t3;
+               t3 = NULL;
+
+       } while(t2);
+
+       return hit;
+}
+
+typedef struct {
+       SculptSession *ss;
+       float *ray_start, *ray_normal;
+       int hit;
+       float dist;
+} SculptRaycastData;
+
+void sculpt_raycast_cb(PBVHNode *node, void *data_v)
+{
+       SculptRaycastData *srd = data_v;
+       MVert *vert = srd->ss->mvert;
+       int i, totface, *faces;
+
+       BLI_pbvh_node_get_faces(node, &faces, &totface);
+
+       for(i = 0; i < totface; ++i) {
+               MFace *f = srd->ss->mface + faces[i];
+               if(ray_face_intersection(srd->ray_start, srd->ray_normal,
+                                        vert[f->v1].co,
+                                        vert[f->v2].co,
+                                        vert[f->v3].co,
+                                        f->v4 ? vert[f->v4].co : NULL,
+                                        &srd->dist)) {
+                       srd->hit = faces[i];
+               }
+       }
+}
+
+/* Do a raycast in the tree to find the 3d brush location
+   (This allows us to ignore the GL depth buffer)
+   Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
+ */
+int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2])
+{
+       ViewContext *vc = paint_stroke_view_context(stroke);
+       float ray_start[3], ray_normal[3];
+       float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
+                        mouse[1] - vc->ar->winrct.ymin};
+       SculptRaycastData srd;
+
+       viewray(vc->ar, vc->v3d, mval, ray_start, ray_normal);
+
+       srd.ss = vc->obact->sculpt;
+       srd.ray_start = ray_start;
+       srd.ray_normal = ray_normal;
+       srd.dist = FLT_MAX;
+       srd.hit = -1;
+       BLI_pbvh_raycast(vc->obact->sculpt->tree, sculpt_raycast_cb, &srd,
+                    ray_start, ray_normal);
+       
+       VecCopyf(out, ray_normal);
+       VecMulf(out, srd.dist);
+       VecAddf(out, out, ray_start);
+
+       return srd.hit != -1;
+}
+
 /* Initialize stroke operator properties */
 static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
 {
-       Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        Object *ob= CTX_data_active_object(C);
        ModifierData *md;
        float scale[3], clip_tolerance[3] = {0,0,0};
@@ -1441,17 +1688,13 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
        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)
 {
        Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        SculptSession *ss = CTX_data_active_object(C)->sculpt;
+       Brush *brush = paint_brush(&sd->paint);
 
        view3d_operator_needs_opengl(C);
 
@@ -1460,37 +1703,36 @@ static void sculpt_brush_stroke_init(bContext *C)
           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);
 }
 
 static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
 {
        StrokeCache *cache = ss->cache;
        Brush *brush = paint_brush(&sd->paint);
-       float *buffer= NULL;
        int i;
 
        /* Restore the mesh before continuing with anchored stroke */
-       if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) {
+       if((brush->flag & BRUSH_ANCHORED) && cache->orig_norms) {
+               ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+               SculptUndoNode *unode;
+
+               /* this could benefit from multithreading... */
+
+               for(unode = lb->first; unode; unode = unode->next) {
+                       float (*co)[3]= unode->co;
+                       int *index= unode->index;
+                       int totvert= unode->totvert;
 
-               if(ss->drawobject)
-                       buffer= (float *)GPU_buffer_lock(ss->drawobject->normals);
+                       for(i = 0; i < totvert; ++i)
+                               VECCOPY(ss->mvert[index[i]].co, co[i]);
+               }
 
                for(i = 0; i < ss->totvert; ++i) {
-                       VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]);
                        ss->mvert[i].no[0] = cache->orig_norms[i][0];
                        ss->mvert[i].no[1] = cache->orig_norms[i][1];
                        ss->mvert[i].no[2] = cache->orig_norms[i][2];
-                       if( buffer != 0 ) {
-                               IndexLink *cur = &ss->drawobject->indices[i];
-                               while( cur != 0 && cur->element != -1 ) {
-                                       VECCOPY(&buffer[cur->element*3],cache->orig_norms[i]);
-                                       cur = cur->next;
-                               }
-                       }
                }
-               if( buffer != 0 )
-                       GPU_buffer_unlock( ss->drawobject->normals );
 
                if(ss->face_normals) {
                        float *fn = ss->face_normals;
@@ -1503,20 +1745,14 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
        }
 }
 
-static void sculpt_post_stroke_free(SculptSession *ss)
-{
-       BLI_freelistN(&ss->damaged_rects);
-       BLI_freelistN(&ss->damaged_verts);
-}
-
 static void sculpt_flush_update(bContext *C)
 {
        Object *ob = CTX_data_active_object(C);
        SculptSession *ss = ob->sculpt;
        ARegion *ar = CTX_wm_region(C);
        MultiresModifierData *mmd = ss->multires;
-
-       calc_damaged_verts(ss);
+       rcti r;
+       int redraw = 0;
 
        if(mmd) {
                if(mmd->undo_verts && mmd->undo_verts != ss->mvert)
@@ -1527,23 +1763,41 @@ static void sculpt_flush_update(bContext *C)
                multires_mark_as_modified(ob);
        }
 
-       ED_region_tag_redraw(ar);
+       BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL);
+       redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r);
+
+       if(redraw) {
+               r.xmin += ar->winrct.xmin + 1;
+               r.xmax += ar->winrct.xmin - 1;
+               r.ymin += ar->winrct.ymin + 1;
+               r.ymax += ar->winrct.ymin - 1;
+               
+               ss->partial_redraw = 1;
+               ED_region_tag_redraw_partial(ar, &r);
+       }
 }
 
 static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
 {
-       ViewContext vc;
-       float cur_depth;
-
-       view3d_set_viewcontext(C, &vc);
-       cur_depth = read_cached_depth(&vc, event->x, event->y);
+       float mouse[2] = {event->x, event->y}, location[3];
+       int over_mesh;
        
-       /* Don't start the stroke until a valid depth is found */
-       if(cur_depth < 1.0 - FLT_EPSILON) {
-               SculptSession *ss = CTX_data_active_object(C)->sculpt;
+       over_mesh = sculpt_stroke_get_location(C, op->customdata, location, mouse);
+       
+       /* Don't start the stroke until mouse goes over the mesh */
+       if(over_mesh) {
+               Object *ob = CTX_data_active_object(C);
+               SculptSession *ss = ob->sculpt;
+               Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+               ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
 
                sculpt_brush_stroke_init_properties(C, op, event, ss);
-               sculptmode_update_all_projverts(ss);
+
+               sculpt_update_cache_invariants(sd, ss, C, op);
+
+               undo_paint_push_begin(UNDO_PAINT_MESH, sculpt_tool_name(sd),
+                       sculpt_undo_restore, sculpt_undo_free);
 
                return 1;
        }
@@ -1556,13 +1810,12 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
        Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
        SculptSession *ss = CTX_data_active_object(C)->sculpt;
 
-       sculpt_update_cache_variants(sd, ss, itemptr);
+       sculpt_update_cache_variants(sd, ss, stroke, itemptr);
        sculpt_restore_mesh(sd, ss);
        do_symmetrical_brush_actions(sd, ss);
 
        /* Cleanup */
        sculpt_flush_update(C);
-       sculpt_post_stroke_free(ss);
 }
 
 static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
@@ -1571,12 +1824,13 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
 
        /* Finished */
        if(ss->cache) {
-               Sculpt *sd = CTX_data_tool_settings(C)->sculpt;         
+               // Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
 
-               request_depth_update(paint_stroke_view_context(stroke)->rv3d);
                sculpt_cache_free(ss->cache);
                ss->cache = NULL;
-               sculpt_undo_push(C, sd);
+
+               undo_paint_push_end(UNDO_PAINT_MESH);
+               // XXX ED_undo_push(C, sculpt_tool_name(sd));
        }
 }
 
@@ -1584,7 +1838,8 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
 {
        sculpt_brush_stroke_init(C);
 
-       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);
 
@@ -1601,19 +1856,19 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
        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);
+       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);
 
        sculpt_flush_update(C);
        sculpt_cache_free(ss->cache);
 
-       sculpt_undo_push(C, sd);
+       // XXX ED_undo_push(C, sculpt_tool_name(sd));
 
        return OPERATOR_FINISHED;
 }
@@ -1649,9 +1904,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
 
        /* The initial 2D location of the mouse */
        RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
-
-       /* The initial screen depth of the mouse */
-       RNA_def_float(ot->srna, "depth", 0.0f, 0.0f, FLT_MAX, "depth", "", 0.0f, FLT_MAX);
 }
 
 /**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
@@ -1665,9 +1917,9 @@ static int sculpt_set_persistent_base(bContext *C, wmOperator *op)
                        MEM_freeN(ss->layer_disps);
                ss->layer_disps = NULL;
 
-               if(ss->mesh_co_orig)
-                       MEM_freeN(ss->mesh_co_orig);
-               ss->mesh_co_orig = NULL;
+               if(ss->layer_co)
+                       MEM_freeN(ss->layer_co);
+               ss->layer_co = NULL;
        }
 
        return OPERATOR_FINISHED;
@@ -1688,6 +1940,13 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
 
 /**** Toggle operator for turning sculpt mode on or off ****/
 
+static void sculpt_init_session(bContext *C, Object *ob)
+{
+       ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+       
+       sculpt_update_mesh_elements(C, 0);
+}
+
 static int sculpt_toggle_mode(bContext *C, wmOperator *op)
 {
        ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1713,7 +1972,8 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
                /* Create sculpt mode session data */
                if(ob->sculpt)
                        free_sculptsession(&ob->sculpt);
-               ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+
+               sculpt_init_session(C, ob);
 
                paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
                
@@ -1745,3 +2005,4 @@ void ED_operatortypes_sculpt()
        WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
        WM_operatortype_append(SCULPT_OT_set_persistent_base);
 }
+
index 15ccacc294abb59d248c00fed01013b93974516c..d0eeacf5ea38d5b87868b871bd9c438377be2a16 100644 (file)
@@ -40,6 +40,7 @@ struct Object;
 struct Scene;
 struct Sculpt;
 struct SculptStroke;
+struct MultiresModifierData;
 
 /* Interface */
 void sculptmode_selectbrush_menu(void);
@@ -47,6 +48,7 @@ void sculptmode_draw_mesh(int);
 void sculpt_paint_brush(char clear);
 void sculpt_stroke_draw(struct SculptStroke *);
 void sculpt_radialcontrol_start(int mode);
+struct MultiresModifierData *sculpt_multires_active(struct Object *ob);
 
 struct Brush *sculptmode_brush(void);
 //void do_symmetrical_brush_actions(struct Sculpt *sd, struct wmOperator *wm, struct BrushAction *a, short *, short *);
@@ -55,6 +57,7 @@ char sculpt_modifiers_active(struct Object *ob);
 void sculpt(Sculpt *sd);
 
 int sculpt_poll(struct bContext *C);
+void sculpt_update_mesh_elements(struct bContext *C, int need_fmap);
 
 /* Stroke */
 struct SculptStroke *sculpt_stroke_new(const int max);
index 22fd77afd88bc2a26c304816717ccd6fb173aa21..1eecefdcf0f11b6c84429d643f4e8ad940e87665 100644 (file)
 #include "ED_mesh.h"
 #include "ED_particle.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 #include "ED_types.h"
 #include "ED_util.h"
 
@@ -2691,7 +2692,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
                   drawFacesSolid() doesn't draw the transparent faces */
                if(ob->dtx & OB_DRAWTRANSP) {
                        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
-                       dm->drawFacesSolid(dm, GPU_enable_material);
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
                        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                        GPU_disable_material();
                }
@@ -2710,7 +2711,7 @@ static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmoot
        return 1;
 }
 
-static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
 {
        Object *ob= base->object;
        Mesh *me = ob->data;
@@ -2783,7 +2784,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                }
        }
        else if(dt==OB_SOLID) {
-               if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire)
+               if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
                        draw_mesh_object_outline(v3d, ob, dm);
 
                glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
@@ -2791,7 +2792,21 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                glEnable(GL_LIGHTING);
                glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
 
-               dm->drawFacesSolid(dm, GPU_enable_material);
+               if(ob->sculpt) {
+                       float planes[4][4];
+                       float (*fpl)[4] = NULL;
+
+                       if(ob->sculpt->partial_redraw) {
+                               sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+                               fpl = planes;
+                               ob->sculpt->partial_redraw = 0;
+                       }
+
+                       dm->drawFacesSolid(dm, fpl, GPU_enable_material);
+               }
+               else
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
+
                GPU_disable_material();
 
                glFrontFace(GL_CCW);
@@ -2802,7 +2817,8 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                } else {
                        UI_ThemeColor(TH_WIRE);
                }
-               dm->drawLooseEdges(dm);
+               if(!ob->sculpt)
+                       dm->drawLooseEdges(dm);
        }
        else if(dt==OB_SHADED) {
                int do_draw= 1; /* to resolve all G.f settings below... */
@@ -2920,7 +2936,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
 }
 
 /* returns 1 if nothing was drawn, for detecting to draw an object center */
-static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
 {
        Object *ob= base->object;
        Object *obedit= scene->obedit;
@@ -2955,10 +2971,6 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                if (obedit!=ob && finalDM)
                        finalDM->release(finalDM);
        }
-//     else if(!em && (G.f & G_SCULPTMODE) &&(scene->sculptdata.flags & SCULPT_DRAW_FAST) &&
-//             OBACT==ob && !sculpt_modifiers_active(ob)) {
-// XXX         sculptmode_draw_mesh(0);
-//     }
        else {
                /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
                if(me->totface<=4 || boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) {
@@ -2970,7 +2982,7 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                                        (check_alpha)? &do_alpha_pass: NULL);
                        }
 
-                       draw_mesh_fancy(scene, v3d, rv3d, base, dt, flag);
+                       draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, flag);
 
                        GPU_end_object_materials();
                        
@@ -5566,7 +5578,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
 
        switch( ob->type) {
                case OB_MESH:
-                       empty_object= draw_mesh_object(scene, v3d, rv3d, base, dt, flag);
+                       empty_object= draw_mesh_object(scene, ar, v3d, rv3d, base, dt, flag);
                        if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself
 
                        break;
@@ -6130,10 +6142,8 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob)
                int ind;
                colors = MEM_mallocN(dm->getNumFaces(dm)*sizeof(MCol)*4,"bbs_mesh_solid");
                for(i=0;i<dm->getNumFaces(dm);i++) {
-                       if( index != 0 )
-                               ind = index[i];
-                       else
-                               ind = i;
+                       ind= ( index )? index[i]: i;
+
                        if (face_sel_mode==0 || !(me->mface[ind].flag&ME_HIDE)) {
                                unsigned int fbindex = index_to_framebuffer(ind+1);
                                for(j=0;j<4;j++) {
@@ -6260,7 +6270,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
                glEnable(GL_LIGHTING);
                
                if(dm) {
-                       dm->drawFacesSolid(dm, GPU_enable_material);
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
                        GPU_end_object_materials();
                }
                else if(edm)
index 64ea574b0117efe394778191de24700f30c5a5ec..75e254339af3798827f6ccabcdc4d035c282c4f6 100644 (file)
@@ -1642,37 +1642,6 @@ void view3d_update_depths(ARegion *ar, View3D *v3d)
        }
 }
 
-/* Enable sculpting in wireframe mode by drawing sculpt object only to the depth buffer */
-static void draw_sculpt_depths(Scene *scene, ARegion *ar, View3D *v3d)
-{
-       Object *ob = OBACT;
-       
-       int dt= MIN2(v3d->drawtype, ob->dt);
-       if(v3d->zbuf==0 && dt>OB_WIRE)
-               dt= OB_WIRE;
-       if(dt == OB_WIRE) {
-               GLboolean depth_on;
-               int orig_vdt = v3d->drawtype;
-               int orig_zbuf = v3d->zbuf;
-               int orig_odt = ob->dt;
-               
-               glGetBooleanv(GL_DEPTH_TEST, &depth_on);
-               v3d->drawtype = ob->dt = OB_SOLID;
-               v3d->zbuf = 1;
-               
-               glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-               glEnable(GL_DEPTH_TEST);
-               draw_object(scene, ar, v3d, BASACT, 0);
-               glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-               if(!depth_on)
-                       glDisable(GL_DEPTH_TEST);
-               
-               v3d->drawtype = orig_vdt;
-               v3d->zbuf = orig_zbuf;
-               ob->dt = orig_odt;
-       }
-}
-
 void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (* func)(void *))
 {
        RegionView3D *rv3d= ar->regiondata;
@@ -1890,8 +1859,8 @@ static CustomDataMask get_viewedit_datamask(bScreen *screen, Scene *scene, Objec
                        mask |= CD_MASK_MCOL;
                if(ob->mode & OB_MODE_WEIGHT_PAINT)
                        mask |= CD_MASK_WEIGHT_MCOL;
-               if(ob->mode & OB_MODE_SCULPT)
-                       mask |= CD_MASK_MDISPS;
+               //if(ob->mode & OB_MODE_SCULPT)
+               //      mask |= CD_MASK_MDISPS;
        }
 
        return mask;
@@ -2128,7 +2097,7 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
        }
 
 //     retopo= retopo_mesh_check() || retopo_curve_check();
-       sculptparticle= (obact && obact->mode & (OB_MODE_SCULPT|OB_MODE_PARTICLE_EDIT)) && !scene->obedit;
+       sculptparticle= (obact && obact->mode & (OB_MODE_PARTICLE_EDIT)) && !scene->obedit;
        if(retopo)
                view3d_update_depths(ar, v3d);
        
@@ -2141,8 +2110,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
        }
        
        if(!retopo && sculptparticle && !(obact && (obact->dtx & OB_DRAWXRAY))) {
-               if(obact && obact->mode & OB_MODE_SCULPT)
-                       draw_sculpt_depths(scene, ar, v3d);
                view3d_update_depths(ar, v3d);
        }
        
@@ -2157,8 +2124,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
        view3d_draw_xray(scene, ar, v3d, 1);    // clears zbuffer if it is used!
        
        if(!retopo && sculptparticle && (obact && (OBACT->dtx & OB_DRAWXRAY))) {
-               if(obact && obact->mode & OB_MODE_SCULPT)
-                       draw_sculpt_depths(scene, ar, v3d);
                view3d_update_depths(ar, v3d);
        }
        
@@ -2180,8 +2145,6 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
        
        ED_region_pixelspace(ar);
        
-       /* Draw Sculpt Mode brush XXX (removed) */
-       
 //     retopo_paint_view_update(v3d);
 //     retopo_draw_paint_lines();
        
index e76dc1aaa00c3f2efa376bbd7f91fd2ebd722f5a..581e427605cdb70a98766f8f6413bf3d18536791 100644 (file)
@@ -1802,12 +1802,9 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot)
 static int view3d_clipping_exec(bContext *C, wmOperator *op)
 {
        RegionView3D *rv3d= CTX_wm_region_view3d(C);
+       ViewContext vc;
+       bglMats mats;
        rcti rect;
-       double mvmatrix[16];
-       double projmatrix[16];
-       double xs, ys, p[3];
-       GLint viewport[4];
-       short val;
 
        rect.xmin= RNA_int_get(op->ptr, "xmin");
        rect.ymin= RNA_int_get(op->ptr, "ymin");
@@ -1820,44 +1817,10 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op)
        /* note; otherwise opengl won't work */
        view3d_operator_needs_opengl(C);
 
-       /* Get the matrices needed for gluUnProject */
-       glGetIntegerv(GL_VIEWPORT, viewport);
-       glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
-       glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
-
-       /* near zero floating point values can give issues with gluUnProject
-               in side view on some implementations */
-       if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
-       if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
-
-       /* Set up viewport so that gluUnProject will give correct values */
-       viewport[0] = 0;
-       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, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
-               VECCOPY(rv3d->clipbb->vec[val], p);
+       view3d_set_viewcontext(C, &vc);
+       view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
+       view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
 
-               gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
-               VECCOPY(rv3d->clipbb->vec[4+val], p);
-       }
-
-       /* then plane equations */
-       for(val=0; val<4; val++) {
-
-               CalcNormFloat(rv3d->clipbb->vec[val], rv3d->clipbb->vec[val==3?0:val+1], rv3d->clipbb->vec[val+4],
-                                         rv3d->clip[val]);
-
-               rv3d->clip[val][3]= - rv3d->clip[val][0]*rv3d->clipbb->vec[val][0]
-                       - rv3d->clip[val][1]*rv3d->clipbb->vec[val][1]
-                       - rv3d->clip[val][2]*rv3d->clipbb->vec[val][2];
-       }
        return OPERATOR_FINISHED;
 }
 
index 9b1b239be70a21c47e4dd03845df9bdf3d4ef203..a953afde0d523b4a27f7006a9f49be35d2891945 100644 (file)
@@ -1411,7 +1411,7 @@ static void do_view3d_tpaintmenu(bContext *C, void *arg, int event)
 #if 0
        switch(event) {
        case 0: /* undo image painting */
-               undo_imagepaint_step(1);
+               ED_paint_undo_step(UNDO_PAINT_IMAGE, 1);
                break;
        }
 
index b13d83c01573a3b01b018e0d9075d2676abe846b..1f7d50e00ed20e2929d33072f2b8852bc633a4d9 100644 (file)
@@ -124,24 +124,24 @@ void view3d_get_view_aligned_coordinate(ViewContext *vc, float *fp, short mval[2
        }
 }
 
-void view3d_get_transformation(ViewContext *vc, Object *ob, bglMats *mats)
+void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats)
 {
        float cpy[4][4];
        int i, j;
 
-       Mat4MulMat4(cpy, ob->obmat, vc->rv3d->viewmat);
+       Mat4MulMat4(cpy, ob->obmat, rv3d->viewmat);
 
        for(i = 0; i < 4; ++i) {
                for(j = 0; j < 4; ++j) {
-                       mats->projection[i*4+j] = vc->rv3d->winmat[i][j];
+                       mats->projection[i*4+j] = rv3d->winmat[i][j];
                        mats->modelview[i*4+j] = cpy[i][j];
                }
        }
 
-       mats->viewport[0] = vc->ar->winrct.xmin;
-       mats->viewport[1] = vc->ar->winrct.ymin;
-       mats->viewport[2] = vc->ar->winx;
-       mats->viewport[3] = vc->ar->winy;       
+       mats->viewport[0] = ar->winrct.xmin;
+       mats->viewport[1] = ar->winrct.ymin;
+       mats->viewport[2] = ar->winx;
+       mats->viewport[3] = ar->winy;   
 }
 
 /* ********************** view3d_select: selection manipulations ********************* */
index 9fbc916c02d2050ea0a33ead9f39a28086578aca..3b210bc718db1ef96186a4ea534b161e1ceebea1 100644 (file)
@@ -481,6 +481,45 @@ void VIEW3D_OT_setobjectascamera(wmOperatorType *ot)
 }
 /* ********************************** */
 
+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++) {
+
+               CalcNormFloat(bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4],
+                             planes[val]);
+
+               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])
 {
index ae1e932bb81d9ae6a2bc810659bac7fda1f429e4..fc2576eef5d687c27584e89f45bd9da9022808b6 100644 (file)
@@ -60,7 +60,7 @@ void ED_editors_exit(bContext *C)
        
        /* frees all editmode undos */
        undo_editmode_clear();
-       undo_imagepaint_clear();
+       ED_undo_paint_free();
        
        for(sce=G.main->scene.first; sce; sce= sce->id.next) {
                if(sce->obedit) {
index d26f7a7a4847250d8d28f948ccbc90c65aadafbf..e20c88ba41feb02c613d25f38fb1f7641fa9b21e 100644 (file)
@@ -124,7 +124,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                SpaceImage *sima= (SpaceImage *)sa->spacedata.first;
                
                if((obact && obact->mode & OB_MODE_TEXTURE_PAINT) || sima->flag & SI_DRAWTOOL) {
-                       undo_imagepaint_step(step);
+                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
 
                        WM_event_add_notifier(C, NC_WINDOW, NULL);
                        return OPERATOR_FINISHED;
@@ -146,7 +146,9 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
                int do_glob_undo= 0;
                
                if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
-                       undo_imagepaint_step(step);
+                       ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step);
+               else if(obact && obact->mode & OB_MODE_SCULPT)
+                       ED_undo_paint_step(C, UNDO_PAINT_MESH, step);
                else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
                        if(step==1)
                                PE_undo(CTX_data_scene(C));
index 662912f9c19e89c799ba4a89eab734e8e763e78f..eceb0cdeca4bee08fdc8c6a4ebc00786b04d6040 100644 (file)
@@ -43,6 +43,7 @@
 #endif
 
 struct DerivedMesh;
+struct GHash;
 
 /* V - vertex, N - normal, T - uv, C - color
    F - float, UB - unsigned byte */
@@ -124,6 +125,16 @@ void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
 GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
 void GPU_drawobject_free( struct DerivedMesh *dm );
 
+/* Buffers for non-DerivedMesh drawing */
+void *GPU_build_buffers(struct GHash *map, struct MVert *mvert,
+                       struct MFace *mface, int *face_indices,
+                       int totface, int *vert_indices, int uniq_verts,
+                       int totvert);
+void GPU_draw_buffers(void *buffers);
+void GPU_update_buffers(void *buffers, struct MVert *mvert,
+                       int *vert_indices, int totvert);
+void GPU_free_buffers(void *buffers);
+
 /* called before drawing */
 void GPU_vertex_setup( struct DerivedMesh *dm );
 void GPU_normal_setup( struct DerivedMesh *dm );
index 9e164f46e4c5938ee0021fa923b6b6f3808c7b1e..14f2c1b6d5bc766f1bd011aa6657b586cf0dc2fa 100644 (file)
@@ -37,6 +37,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "BLI_arithb.h"
+#include "BLI_ghash.h"
 
 #include "DNA_meshdata_types.h"
 
@@ -376,6 +377,156 @@ void GPU_drawobject_free( DerivedMesh *dm )
        dm->drawObject = 0;
 }
 
+/* Convenience struct for building the VBO.
+   TODO: check that (lack-of) padding is OK,
+   also check performance of short vs float for normals */
+typedef struct {
+       float co[3];
+       short no[3];
+       
+       char pad[14];
+} VertexBufferFormat;
+
+typedef struct {
+       unsigned int vert_buf, tri_buf;
+       unsigned short tot_tri;
+} GPU_Buffers;
+
+void GPU_update_buffers2(void *buffers_v, MVert *mvert,
+                       int *vert_indices, int totvert)
+{
+       GPU_Buffers *buffers = buffers_v;
+       VertexBufferFormat *vert_data;
+       int i;
+
+       vert_data = MEM_callocN(sizeof(VertexBufferFormat) * totvert, "bad");
+
+       for(i = 0; i < totvert; ++i) {
+               MVert *v = mvert + vert_indices[i];
+               VertexBufferFormat *out = vert_data + i;
+
+               VecCopyf(out->co, v->co);
+               memcpy(out->no, v->no, sizeof(short) * 3);
+       }
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+       glBufferData(GL_ARRAY_BUFFER,
+                    sizeof(VertexBufferFormat) * totvert,
+                    vert_data, GL_STATIC_DRAW);
+
+       MEM_freeN(vert_data);
+}
+
+void GPU_update_buffers(void *buffers_v, MVert *mvert,
+                       int *vert_indices, int totvert)
+{
+       GPU_Buffers *buffers = buffers_v;
+       VertexBufferFormat *vert_data;
+       int i;
+
+       /* Build VBO */
+       glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+       glBufferData(GL_ARRAY_BUFFER,
+                    sizeof(VertexBufferFormat) * totvert,
+                    NULL, GL_STATIC_DRAW);
+       vert_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+       for(i = 0; i < totvert; ++i) {
+               MVert *v = mvert + vert_indices[i];
+               VertexBufferFormat *out = vert_data + i;
+
+               VecCopyf(out->co, v->co);
+               memcpy(out->no, v->no, sizeof(short) * 3);
+       }
+       glUnmapBuffer(GL_ARRAY_BUFFER);
+
+       //printf("node updated %p\n", buffers_v);
+}
+
+void *GPU_build_buffers(GHash *map, MVert *mvert, MFace *mface,
+                       int *face_indices, int totface,
+                       int *vert_indices, int tot_uniq_verts,
+                       int totvert)
+{
+       GPU_Buffers *buffers;
+       unsigned short *tri_data;
+       int i, j, k, tottri;
+
+       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+
+       /* Count the number of triangles */
+       for(i = 0, tottri = 0; i < totface; ++i)
+               tottri += mface[face_indices[i]].v4 ? 2 : 1;
+
+       /* Generate index buffer object */
+       glGenBuffers(1, &buffers->tri_buf);
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->tri_buf);
+       glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+                    sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW);
+
+       /* Fill the triangle buffer */
+       tri_data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+       for(i = 0; i < totface; ++i) {
+               MFace *f = mface + face_indices[i];
+               int v[3] = {f->v1, f->v2, f->v3};
+
+               for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
+                       for(k = 0; k < 3; ++k) {
+                               void *value, *key = SET_INT_IN_POINTER(v[k]);
+                               int vbo_index;
+
+                               value = BLI_ghash_lookup(map, key);
+                               vbo_index = GET_INT_FROM_POINTER(value);
+
+                               if(vbo_index < 0) {
+                                       vbo_index = -vbo_index +
+                                               tot_uniq_verts - 1;
+                               }
+
+                               *tri_data = vbo_index;
+                               ++tri_data;
+                       }
+                       v[0] = f->v4;
+                       v[1] = f->v1;
+                       v[2] = f->v3;
+               }
+       }
+       glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+       /* Build VBO */
+       glGenBuffers(1, &buffers->vert_buf);
+       GPU_update_buffers(buffers, mvert, vert_indices, totvert);
+
+       buffers->tot_tri = tottri;
+
+       return buffers;
+}
+
+void GPU_draw_buffers(void *buffers_v)
+{
+       GPU_Buffers *buffers = buffers_v;
+
+       glBindBuffer(GL_ARRAY_BUFFER, buffers->vert_buf);
+       glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers->tri_buf);
+
+       glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), 0);
+       glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)12);
+
+       glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, GL_UNSIGNED_SHORT, 0);
+}
+
+void GPU_free_buffers(void *buffers_v)
+{
+       if(buffers_v) {
+               GPU_Buffers *buffers = buffers_v;
+               
+               glDeleteBuffers(1, &buffers->vert_buf);
+               glDeleteBuffers(1, &buffers->tri_buf);
+
+               MEM_freeN(buffers);
+       }
+}
+
 GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
 {
        GPUBuffer *buffer;
index d53a7833d0ed480960fdd91cd1272f4347d3a102..48e361afdaeb047cf7bf54ed2a825d140e23f899 100644 (file)
@@ -182,10 +182,11 @@ typedef struct PartialVisibility {
 } PartialVisibility;
 
 /* mvert->flag (1=SELECT) */
-#define ME_SPHERETEST  2
-#define ME_SPHERETEMP  4
-#define ME_HIDE                        16
+#define ME_SPHERETEST          2
+#define ME_SPHERETEMP          4
+#define ME_HIDE                                16
 #define ME_VERT_MERGED         (1<<6)
+#define ME_VERT_PBVH_UPDATE    (1<<7)
 
 /* medge->flag (1=SELECT)*/
 #define ME_EDGEDRAW                    (1<<1)
index bafe8cc316225ea3770f33c506ea8e7c69d51372..810b34a746eba37d8e8b7d46fe0c7393ea508508 100644 (file)
@@ -481,7 +481,7 @@ typedef struct Paint {
        void *paint_cursor;
        unsigned char paint_cursor_col[4];
 
-       int pad;
+       int flags;
 } Paint;
 
 typedef struct ImagePaintSettings {
@@ -1046,14 +1046,17 @@ typedef struct Scene {
 #define FFMPEG_MULTIPLEX_AUDIO  1
 #define FFMPEG_AUTOSPLIT_OUTPUT 2
 
+/* Paint.flags */
+typedef enum {
+       PAINT_SHOW_BRUSH = 1
+} PaintFlags;
+
 /* Sculpt.flags */
+/* These can eventually be moved to paint flags? */
 typedef enum SculptFlags {
        SCULPT_SYMM_X = 1,
        SCULPT_SYMM_Y = 2,
        SCULPT_SYMM_Z = 4,
-       SCULPT_INPUT_SMOOTH = 8,
-       SCULPT_DRAW_FAST = 16,
-       SCULPT_DRAW_BRUSH = 32,
        SCULPT_LOCK_X = 64,
        SCULPT_LOCK_Y = 128,
        SCULPT_LOCK_Z = 256
index 481abc983c26b89462939c87cda27d22b86b88b2..89e295967466b5962ef8539b9d74d3b09da2c930 100644 (file)
@@ -170,6 +170,10 @@ static void rna_def_paint(BlenderRNA *brna)
        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.");
+
+       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", "");
 }
 
 static void rna_def_sculpt(BlenderRNA  *brna)
@@ -203,14 +207,6 @@ static void rna_def_sculpt(BlenderRNA  *brna)
        prop= RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Z);
        RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices.");
-
-       prop= RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DRAW_BRUSH);
-       RNA_def_property_ui_text(prop, "Show Brush", "");
-
-       prop= RNA_def_property(srna, "partial_redraw", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DRAW_FAST);
-       RNA_def_property_ui_text(prop, "Partial Redraw", "Optimize sculpting by only refreshing modified faces.");
 }
 
 static void rna_def_vertex_paint(BlenderRNA *brna)
index 072083e58a76c19893b2ffee687d6260ecf56d17..cb8970a356fac24d9e4164789b89e092eefc99f1 100644 (file)
@@ -1710,8 +1710,12 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
                        if(origindex) {
                                for(a=0; a<totface; a++)
                                        strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]);
-                               strandbuf->totbound++;
                        }
+                       else {
+                               for(a=0; a<totface; a++)
+                                       strandbuf->totbound= MAX2(strandbuf->totbound, a);
+                       }
+
                        strandbuf->totbound++;
                        strandbuf->bound= MEM_callocN(sizeof(StrandBound)*strandbuf->totbound, "StrandBound");
                        sbound= strandbuf->bound;