diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-11-25 16:40:43 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-11-25 16:40:43 +0300 |
commit | 134935a8db7fe6137bb8a508771757beeb68b2b3 (patch) | |
tree | f04d8dbe44cab60ecd2e5279bb1559dcaa31c7f0 /source/blender | |
parent | a1bf207be31f4bb578e920bc472cc3471a6554ca (diff) |
Sculpt: Grid based PBVH
* PBVH can now be created contain both from face grids or standard
meshes. The former is much quicker to build for high res meshes.
* Moved some drawing code into pbvh (mostly for the frustum test).
* Moved ray intersection code into pbvh.
* GPU buffers also can be built from either mesh or grids now.
* Updated sculpt code to work with this. The ugly part is that there
is now a macro for iterating over vertices, to handle both cases,
and some duplicated code for e.g. undo.
* Smooth brush does not work yet with grids.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/intern/cdderivedmesh.c | 73 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 13 | ||||
-rw-r--r-- | source/blender/blenlib/BLI_pbvh.h | 110 | ||||
-rw-r--r-- | source/blender/blenlib/intern/pbvh.c | 487 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 643 | ||||
-rw-r--r-- | source/blender/gpu/gpu_buffers.h | 10 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 134 |
7 files changed, 969 insertions, 501 deletions
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index e64d8a24934..3007564e333 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -197,7 +197,7 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) Mesh *me= ob->data; cddm->pbvh = BLI_pbvh_new(); - BLI_pbvh_build(cddm->pbvh, me->mface, me->mvert, + BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, me->totface, me->totvert); } @@ -393,60 +393,6 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm) } } -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, void *data) -{ - float (*planes)[4] = data; - int i, axis; - float vmin[3], vmax[3], bb_min[3], bb_max[3]; - - BLI_pbvh_node_get_BB(node, bb_min, bb_max); - - 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(dot_v3v3(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)) @@ -468,26 +414,11 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, 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; + BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors); glShadeModel(GL_FLAT); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index e465d17f498..30766931a0b 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -819,6 +819,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert) for(x = 1; x < edgeSize - 1; x++, i++) { vd= ccgSubSurf_getEdgeData(ss, e, x); copy_v3_v3(mvert[i].co, vd->co); + /* TODO CCGSubsurf does not set these */ normal_float_to_short_v3(mvert[i].no, vd->no); } } @@ -1230,8 +1231,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) char *faceFlags = ccgdm->faceFlags; int step = 1; //(fast)? gridSize-1: 1; -#if 0 - if(ccgdm->pbvh && ccgdm->multires.mmd && !fast) { + if(ccgdm->pbvh && ccgdm->multires.mmd) { // && !fast) { CCGFace **faces; int totface; @@ -1252,7 +1252,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) return; } -#endif fi = ccgSubSurf_getFaceIterator(ss); for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) { @@ -2135,12 +2134,12 @@ static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm) static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) { CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm; - //int gridSize, numGrids; + int gridSize, numGrids; if(ccgdm->pbvh) return ccgdm->pbvh; - /*if(ccgdm->multires.mmd) { + if(ccgdm->multires.mmd) { ccgdm_create_grids(dm); gridSize = ccgDM_getGridSize(dm); @@ -2150,11 +2149,11 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, numGrids, gridSize, (void**)ccgdm->gridFaces); } - else*/ if(ob->type == OB_MESH) { + else if(ob->type == OB_MESH) { Mesh *me= ob->data; ccgdm->pbvh = BLI_pbvh_new(); - BLI_pbvh_build(ccgdm->pbvh, me->mface, me->mvert, + BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert, me->totface, me->totvert); } diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h index 360a9937498..5c5277dc091 100644 --- a/source/blender/blenlib/BLI_pbvh.h +++ b/source/blender/blenlib/BLI_pbvh.h @@ -27,6 +27,7 @@ struct MFace; struct MVert; +struct DMGridData; struct PBVH; struct PBVHNode; struct ListBase; @@ -44,12 +45,12 @@ 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, +void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, int totface, int totvert); +void BLI_pbvh_build_grids(PBVH *bvh, struct DMGridData **grids, int totgrid, + int gridsize, void **gridfaces); 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) */ @@ -69,6 +70,14 @@ void BLI_pbvh_search_gather(PBVH *bvh, void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, float ray_start[3], float ray_normal[3], int original); +int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], + float ray_start[3], float ray_normal[3], float *dist); + +/* Drawing */ + +void BLI_pbvh_node_draw(PBVHNode *node, void *data); +int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); +void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3]); /* Node Access */ @@ -84,11 +93,11 @@ typedef enum { void BLI_pbvh_node_mark_update(PBVHNode *node); -void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, - int *totvert, int *allverts); -void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, - int **face_vert_indices, int *totface); -void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node); +void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, + int **grid_indices, int *totgrid, int *maxgrid, int *gridsize); +void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, + int *uniquevert, int *totvert); + void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]); void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]); @@ -96,6 +105,91 @@ void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); +void BLI_pbvh_get_grid_updates(PBVH *bvh, void ***gridfaces, int *totface); + +/* Vertex Iterator */ + +/* this iterator has quite a lot of code, but it's designed to: + - allow the compiler to eliminate dead code and variables + - spend most of the time in the relatively simple inner loop */ + +#define PBVH_ITER_ALL 0 +#define PBVH_ITER_UNIQUE 1 + +typedef struct PBVHVertexIter { + /* iteration */ + int g; + int width; + int height; + int skip; + int gx; + int gy; + int i; + + /* grid */ + struct DMGridData **grids; + struct DMGridData *grid; + int *grid_indices; + int totgrid; + int gridsize; + + /* mesh */ + struct MVert *mverts; + int totvert; + int *vert_indices; + + /* result: these are all computed in the macro, but we assume + that compiler optimizations will skip the ones we don't use */ + struct MVert *mvert; + float *co; + short *no; + float *fno; +} PBVHVertexIter; + +void BLI_pbvh_node_verts_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode); + +#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ + /* XXX breaks aliasing! */ \ + BLI_pbvh_node_verts_iter_init(bvh, node, &vi, mode); \ + \ + for(vi.i=0, vi.g=0; vi.g<vi.totgrid; vi.g++) { \ + if(vi.grids) { \ + vi.width= vi.gridsize; \ + vi.height= vi.gridsize; \ + vi.grid= vi.grids[vi.grid_indices[vi.g]]; \ + vi.skip= 0; \ + \ + /*if(mode == PVBH_ITER_UNIQUE) { \ + vi.grid += subm->grid.offset; \ + vi.skip= subm->grid.skip; \ + vi.grid -= skip; \ + }*/ \ + } \ + else { \ + vi.width= vi.totvert; \ + vi.height= 1; \ + } \ + \ + for(vi.gy=0; vi.gy<vi.height; vi.gy++) { \ + if(vi.grid) vi.grid += vi.skip; \ + \ + for(vi.gx=0; vi.gx<vi.width; vi.gx++, vi.i++) { \ + if(vi.grid) { \ + vi.co= vi.grid->co; \ + vi.fno= vi.grid->no; \ + vi.grid++; \ + } \ + else { \ + vi.mvert= &vi.mverts[vi.vert_indices[vi.gx]]; \ + vi.co= vi.mvert->co; \ + vi.no= vi.mvert->no; \ + } \ + +#define BLI_pbvh_vertex_iter_end \ + } \ + } \ + } + #endif /* BLI_PBVH_H */ diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c index c2f0705d8c2..023db54eb1c 100644 --- a/source/blender/blenlib/intern/pbvh.c +++ b/source/blender/blenlib/intern/pbvh.c @@ -32,6 +32,7 @@ #include "BLI_ghash.h" #include "BLI_pbvh.h" +#include "BKE_DerivedMesh.h" #include "BKE_mesh.h" #include "BKE_utildefines.h" @@ -87,12 +88,12 @@ struct PBVHNode { /* For internal nodes */ int children_offset; - /* Pointer into bvh face_indices */ - int *face_indices; + /* Pointer into bvh prim_indices */ + int *prim_indices; int *face_vert_indices; - unsigned short totface; - unsigned short uniq_verts, face_verts; + unsigned int totprim; + unsigned int uniq_verts, face_verts; char flag; }; @@ -101,14 +102,22 @@ struct PBVH { PBVHNode *nodes; int node_mem_count, totnode; - int *face_indices; - int totface; + int *prim_indices; + int totprim; int totvert; + int leaf_limit; + /* Mesh data */ MVert *verts; MFace *faces; + /* Grid Data */ + DMGridData **grids; + void **gridfaces; + int totgrid; + int gridsize; + /* Only used during BVH build and update, don't need to remain valid after */ BLI_bitmap vert_bitmap; @@ -201,12 +210,12 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) BB_reset(&vb); if(node->flag & PBVH_Leaf) { - int i, totvert= node->uniq_verts + node->face_verts; + PBVHVertexIter vd; - for(i = 0; i < totvert; ++i) { - float *co= bvh->verts[node->vert_indices[i]].co; - BB_expand(&vb, co); + BLI_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) { + BB_expand(&vb, vd.co); } + BLI_pbvh_vertex_iter_end; } else { BB_expand_with_bb(&vb, @@ -220,28 +229,28 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) /* 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, +static int partition_indices(int *prim_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--); + for(; prim_bbc[prim_indices[i]].bcentroid[axis] < mid; i++); + for(; mid < prim_bbc[prim_indices[j]].bcentroid[axis]; j--); if(!(i < j)) return i; - SWAP(int, face_indices[i], face_indices[j]); + SWAP(int, prim_indices[i], prim_indices[j]); i++; } } -void check_partitioning(int *face_indices, int lo, int hi, int axis, +void check_partitioning(int *prim_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]; + const float c = prim_bbc[prim_indices[i]].bcentroid[axis]; if((i < index_of_2nd_partition && c > mid) || (i > index_of_2nd_partition && c < mid)) { @@ -269,8 +278,8 @@ static void grow_nodes(PBVH *bvh, int totnode) /* Add a vertex to the map, with a positive value for unique vertices and a negative value for additional vertices */ static int map_insert_vert(PBVH *bvh, GHash *map, - unsigned short *face_verts, - unsigned short *uniq_verts, int vertex) + unsigned int *face_verts, + unsigned int *uniq_verts, int vertex) { void *value, *key = SET_INT_IN_POINTER(vertex); @@ -293,7 +302,7 @@ static int map_insert_vert(PBVH *bvh, GHash *map, } /* Find vertices used by the faces in this node and update the draw buffers */ -static void build_leaf_node(PBVH *bvh, PBVHNode *node) +static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) { GHashIterator *iter; GHash *map; @@ -302,13 +311,13 @@ static void build_leaf_node(PBVH *bvh, PBVHNode *node) map = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); node->uniq_verts = node->face_verts = 0; - totface= node->totface; + totface= node->totprim; node->face_vert_indices = MEM_callocN(sizeof(int) * 4*totface, "bvh node face vert indices"); for(i = 0; i < totface; ++i) { - MFace *f = bvh->faces + node->face_indices[i]; + MFace *f = bvh->faces + node->prim_indices[i]; int sides = f->v4 ? 4 : 3; for(j = 0; j < sides; ++j) { @@ -341,15 +350,22 @@ static void build_leaf_node(PBVH *bvh, PBVHNode *node) node->face_vert_indices[i]= -node->face_vert_indices[i] + node->uniq_verts - 1; node->draw_buffers = - GPU_build_buffers(map, bvh->verts, bvh->faces, - node->face_indices, - node->totface, node->vert_indices, + GPU_build_mesh_buffers(map, bvh->verts, bvh->faces, + node->prim_indices, + node->totprim, node->vert_indices, node->uniq_verts, node->uniq_verts + node->face_verts); BLI_ghash_free(map, NULL, NULL); } +static void build_grids_leaf_node(PBVH *bvh, PBVHNode *node) +{ + node->draw_buffers = + GPU_build_grid_buffers(bvh->grids, node->prim_indices, + node->totprim, bvh->gridsize); +} + /* Recursively build a node in the tree vb is the voxel box around all of the primitives contained in @@ -368,21 +384,25 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, BB cb_backing; /* Decide whether this is a leaf or not */ - if(count <= LEAF_LIMIT) { + // XXX adapt leaf limit for grids + if(count <= bvh->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; + bvh->nodes[node_index].prim_indices = bvh->prim_indices + offset; + bvh->nodes[node_index].totprim = 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])); + bvh->prim_indices[i])); } - build_leaf_node(bvh, bvh->nodes + node_index); + if(bvh->faces) + build_mesh_leaf_node(bvh, bvh->nodes + node_index); + else + build_grids_leaf_node(bvh, bvh->nodes + node_index); bvh->nodes[node_index].orig_vb= bvh->nodes[node_index].vb; /* Done with this subtree */ @@ -397,7 +417,7 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, cb = &cb_backing; BB_reset(cb); for(i = offset + count - 1; i >= offset; --i) - BB_expand(cb, prim_bbc[bvh->face_indices[i]].bcentroid); + BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid); } } @@ -405,16 +425,16 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, for(i = offset + count - 1; i >= offset; --i) { BB_expand_with_bb(&bvh->nodes[node_index].vb, - (BB*)(prim_bbc + bvh->face_indices[i])); + (BB*)(prim_bbc + bvh->prim_indices[i])); } bvh->nodes[node_index].orig_vb= bvh->nodes[node_index].vb; - end = partition_indices(bvh->face_indices, offset, offset + count - 1, + end = partition_indices(bvh->prim_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, + check_partitioning(bvh->prim_indices, offset, offset + count - 1, axis, (cb->bmax[axis] + cb->bmin[axis]) * 0.5f, prim_bbc, end); @@ -425,21 +445,18 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, prim_bbc, end, offset + count - end); } -/* Do a full rebuild */ -void BLI_pbvh_build(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert) +static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) { - BBC *prim_bbc = NULL; - BB cb; - int i, j; + int i; - if(totface != bvh->totface) { - bvh->totface = totface; + if(totprim != bvh->totprim) { + bvh->totprim = totprim; 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; + if(bvh->prim_indices) MEM_freeN(bvh->prim_indices); + bvh->prim_indices = MEM_callocN(sizeof(int) * totprim, + "bvh prim indices"); + for(i = 0; i < totprim; ++i) + bvh->prim_indices[i] = i; bvh->totnode = 0; if(bvh->node_mem_count < 100) { bvh->node_mem_count = 100; @@ -449,10 +466,22 @@ void BLI_pbvh_build(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totv } } + bvh->totnode = 1; + build_sub(bvh, 0, cb, prim_bbc, 0, totprim); +} + +/* Do a full rebuild with on Mesh data structure */ +void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert) +{ + BBC *prim_bbc = NULL; + BB cb; + int i, j; + bvh->faces = faces; bvh->verts = verts; bvh->vert_bitmap = BLI_bitmap_new(totvert); - bvh->totvert= totvert; + bvh->totvert = totvert; + bvh->leaf_limit = LEAF_LIMIT; BB_reset(&cb); @@ -474,13 +503,50 @@ void BLI_pbvh_build(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totv BB_expand(&cb, bbc->bcentroid); } - bvh->totnode = 1; - build_sub(bvh, 0, &cb, prim_bbc, 0, totface); + pbvh_build(bvh, &cb, prim_bbc, totface); MEM_freeN(prim_bbc); MEM_freeN(bvh->vert_bitmap); } +/* Do a full rebuild with on Grids data structure */ +void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids, int totgrid, + int gridsize, void **gridfaces) +{ + BBC *prim_bbc = NULL; + BB cb; + int i, j; + + bvh->grids= grids; + bvh->gridfaces= gridfaces; + bvh->totgrid= totgrid; + bvh->gridsize= gridsize; + bvh->leaf_limit = MAX2(LEAF_LIMIT/((gridsize-1)*(gridsize-1)), 1); + + BB_reset(&cb); + + /* For each grid, store the AABB and the AABB centroid */ + prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc"); + + for(i = 0; i < totgrid; ++i) { + DMGridData *grid= grids[i]; + BBC *bbc = prim_bbc + i; + + BB_reset((BB*)bbc); + + for(j = 0; j < gridsize*gridsize; ++j) + BB_expand((BB*)bbc, grid[j].co); + + BBC_update_centroid(bbc); + + BB_expand(&cb, bbc->bcentroid); + } + + pbvh_build(bvh, &cb, prim_bbc, totgrid); + + MEM_freeN(prim_bbc); +} + PBVH *BLI_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); @@ -490,34 +556,27 @@ PBVH *BLI_pbvh_new(void) void BLI_pbvh_free(PBVH *bvh) { + PBVHNode *node; 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[i].face_vert_indices); + node= &bvh->nodes[i]; + + if(node->flag & PBVH_Leaf) { + if(node->draw_buffers) + GPU_free_buffers(node->draw_buffers); + if(node->vert_indices) + MEM_freeN(node->vert_indices); + if(node->face_vert_indices) + MEM_freeN(node->face_vert_indices); } } MEM_freeN(bvh->nodes); - MEM_freeN(bvh->face_indices); + MEM_freeN(bvh->prim_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; @@ -646,7 +705,7 @@ void BLI_pbvh_search_callback(PBVH *bvh, while((node=pbvh_iter_next(&iter))) if(node->flag & PBVH_Leaf) - do_hit_callback(bvh, node, hcb, hit_data); + hcb(node, hit_data); pbvh_iter_end(&iter); } @@ -667,6 +726,9 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, float (*vnor)[3]; int n; + if(bvh->grids) + return; + /* 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"); @@ -688,8 +750,8 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, if((node->flag & PBVH_UpdateNormals)) { int i, j, totface, *faces; - faces= node->face_indices; - totface= node->totface; + faces= node->prim_indices; + totface= node->totprim; for(i = 0; i < totface; ++i) { MFace *f= bvh->faces + faces[i]; @@ -792,11 +854,20 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) 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); + if(bvh->grids) { + GPU_update_grid_buffers(node->draw_buffers, + bvh->grids, + node->prim_indices, + node->totprim, + bvh->gridsize); + } + else { + GPU_update_mesh_buffers(node->draw_buffers, + bvh->verts, + node->vert_indices, + node->uniq_verts + + node->face_verts); + } node->flag &= ~PBVH_UpdateDrawBuffers; } @@ -877,6 +948,53 @@ void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) copy_v3_v3(bb_max, bb.bmax); } +void BLI_pbvh_get_grid_updates(PBVH *bvh, void ***gridfaces, int *totface) +{ + PBVHIter iter; + PBVHNode *node; + GHashIterator *hiter; + GHash *map; + void *face, **faces; + int i, tot; + + map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + pbvh_iter_begin(&iter, bvh, NULL, NULL); + + while((node=pbvh_iter_next(&iter))) { + if(node->flag & PBVH_UpdateNormals) { + for(i = 0; i < node->totprim; ++i) { + face= bvh->gridfaces[node->prim_indices[i]]; + BLI_ghash_insert(map, face, face); + } + + node->flag &= ~PBVH_UpdateNormals; + } + } + + pbvh_iter_end(&iter); + + tot= BLI_ghash_size(map); + if(tot == 0) { + *totface= 0; + *gridfaces= NULL; + BLI_ghash_free(map, NULL, NULL); + return; + } + + faces= MEM_callocN(sizeof(void*)*tot, "PBVH Grid Faces"); + + for(hiter = BLI_ghashIterator_new(map), i = 0; + !BLI_ghashIterator_isDone(hiter); + BLI_ghashIterator_step(hiter), ++i) + faces[i]= BLI_ghashIterator_getKey(hiter); + + BLI_ghash_free(map, NULL, NULL); + + *totface= tot; + *gridfaces= faces; +} + /***************************** Node Access ***********************************/ void BLI_pbvh_node_mark_update(PBVHNode *node) @@ -891,16 +1009,32 @@ void BLI_pbvh_node_get_verts(PBVHNode *node, int **vert_indices, int *totvert, i if(allvert) *allvert= node->uniq_verts + node->face_verts; } -void BLI_pbvh_node_get_faces(PBVHNode *node, int **face_indices, int **face_vert_indices, int *totface) +void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) { - if(face_indices) *face_indices= node->face_indices; - if(face_vert_indices) *face_vert_indices= node->face_vert_indices; - if(totface) *totface= node->totface; + if(bvh->grids) { + *totvert= node->totprim*bvh->gridsize*bvh->gridsize; + *uniquevert= *totvert; + } + else { + *uniquevert= node->uniq_verts; + *totvert= node->uniq_verts + node->face_verts; + } } -void *BLI_pbvh_node_get_draw_buffers(PBVHNode *node) +void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize) { - return node->draw_buffers; + if(bvh->grids) { + if(grid_indices) *grid_indices= node->prim_indices; + if(totgrid) *totgrid= node->totprim; + if(maxgrid) *maxgrid= bvh->totgrid; + if(gridsize) *gridsize= bvh->gridsize; + } + else { + *grid_indices= NULL; + *totgrid= 0; + *maxgrid= 0; + *gridsize= 0; + } } void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) @@ -936,7 +1070,7 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v) BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); else BLI_pbvh_node_get_BB(node, bb_min, bb_max); - + copy_v3_v3(bbox[0], bb_min); copy_v3_v3(bbox[1], bb_max); @@ -988,3 +1122,194 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, BLI_pbvh_search_callback(bvh, ray_aabb_intersect, &rcd, cb, data); } +/* XXX: Code largely copied from bvhutils.c, could be unified */ +/* Returns 1 if a better intersection has been found */ +static int ray_face_intersection(float ray_start[3], float ray_normal[3], + float *t0, float *t1, float *t2, float *t3, + float *fdist) +{ + int hit = 0; + + do + { + float dist = FLT_MAX; + + if(!isect_ray_tri_v3(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; +} + +int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], + float ray_start[3], float ray_normal[3], float *dist) +{ + int hit= 0; + + if(bvh->faces) { + MVert *vert = bvh->verts; + int *faces= node->prim_indices; + int *face_verts= node->face_vert_indices; + int totface= node->totprim; + int i; + + for(i = 0; i < totface; ++i) { + MFace *f = bvh->faces + faces[i]; + + if(origco) { + /* intersect with backuped original coordinates */ + hit |= ray_face_intersection(ray_start, ray_normal, + origco[face_verts[i*4+0]], + origco[face_verts[i*4+1]], + origco[face_verts[i*4+2]], + f->v4? origco[face_verts[i*4+3]]: NULL, + dist); + } + else { + /* intersect with current coordinates */ + hit |= ray_face_intersection(ray_start, ray_normal, + vert[f->v1].co, + vert[f->v2].co, + vert[f->v3].co, + f->v4 ? vert[f->v4].co : NULL, + dist); + } + } + } + else { + int totgrid= node->totprim; + int gridsize= bvh->gridsize; + int i, x, y; + + for(i = 0; i < totgrid; ++i) { + DMGridData *grid= bvh->grids[node->prim_indices[i]]; + + for(y = 0; y < gridsize-1; ++y) { + for(x = 0; x < gridsize-1; ++x) { + if(origco) { + hit |= ray_face_intersection(ray_start, ray_normal, + origco[y*gridsize + x], + origco[y*gridsize + x+1], + origco[(y+1)*gridsize + x+1], + origco[(y+1)*gridsize + x], + dist); + } + else { + hit |= ray_face_intersection(ray_start, ray_normal, + grid[y*gridsize + x].co, + grid[y*gridsize + x+1].co, + grid[(y+1)*gridsize + x+1].co, + grid[(y+1)*gridsize + x].co, + dist); + } + } + } + + if(origco) + origco += gridsize*gridsize; + } + } + + return hit; +} + +#if 0 +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; +} +#endif + +void BLI_pbvh_node_draw(PBVHNode *node, void *data) +{ + GPU_draw_buffers(node->draw_buffers); +} + +/* 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 BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) +{ + float (*planes)[4] = data; + int i, axis; + float vmin[3], vmax[3], bb_min[3], bb_max[3]; + + BLI_pbvh_node_get_BB(node, bb_min, bb_max); + + 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(dot_v3v3(planes[i], vmin) + planes[i][3] > 0) + return 0; + } + + return 1; +} + +void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3]) +{ + BLI_pbvh_update(bvh, PBVH_UpdateNormals|PBVH_UpdateDrawBuffers, face_nors); + + if(planes) { + BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB, + planes, BLI_pbvh_node_draw, NULL); + } + else { + BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, NULL); + } +} + +void BLI_pbvh_node_verts_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode) +{ + memset(vi, 0, sizeof(PBVHVertexIter)); + vi->grids= bvh->grids; + vi->grid_indices= node->prim_indices; + vi->totgrid= (bvh->grids)? node->totprim: 1; + vi->gridsize= bvh->gridsize; + + vi->totvert= node->uniq_verts; + if(mode == PBVH_ITER_ALL) + vi->totvert += node->face_verts; + vi->vert_indices= node->vert_indices; + vi->mverts= bvh->verts; +} + diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 873bbc2baa6..c9e351458ad 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -267,13 +267,21 @@ 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]; short (*no)[3]; - int *index; int totvert; + + /* non-multires */ + int maxvert; /* to verify if totvert it still the same */ + int *index; /* to restore into right location */ + + /* multires */ + int maxgrid; /* same for grid */ + int gridsize; /* same for grid */ + int totgrid; /* to restore into right location */ + int *grids; /* to restore into right location */ } SculptUndoNode; static void update_cb(PBVHNode *node, void *data) @@ -284,33 +292,54 @@ static void update_cb(PBVHNode *node, void *data) static void sculpt_undo_restore(bContext *C, ListBase *lb) { Object *ob = CTX_data_active_object(C); + DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, 0); SculptSession *ss = ob->sculpt; SculptUndoNode *unode; MVert *mvert; MultiresModifierData *mmd; int *index; - int i, totvert, update= 0; + int i, j, 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; + if(unode->maxvert) { + /* regular mesh restore */ + if(ss->totvert != unode->maxvert) + continue; - for(i=0; i<totvert; i++) { - float tmp[3]; + index= unode->index; + mvert= ss->mvert; - copy_v3_v3(tmp, mvert[index[i]].co); - copy_v3_v3(mvert[index[i]].co, unode->co[i]); - copy_v3_v3(unode->co[i], tmp); - - mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + for(i=0; i<unode->totvert; i++) { + swap_v3_v3(mvert[index[i]].co, unode->co[i]); + mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE; + } + } + else if(unode->maxgrid) { + /* multires restore */ + DMGridData **grids, *grid; + float (*co)[3]; + int gridsize; + + if(dm->getNumGrids(dm) != unode->maxgrid) + continue; + if(dm->getGridSize(dm) != unode->gridsize) + continue; + + grids= dm->getGridData(dm); + gridsize= dm->getGridSize(dm); + + co = unode->co; + for(j=0; j<unode->totgrid; j++) { + grid= grids[unode->grids[j]]; + + for(i=0; i<gridsize*gridsize; i++, co++) + swap_v3_v3(grid[i].co, co[0]); + } } update= 1; @@ -323,15 +352,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) BLI_pbvh_search_callback(ss->tree, NULL, NULL, update_cb, NULL); BLI_pbvh_update(ss->tree, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, 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); - } + if((mmd=sculpt_multires_active(ob))) + multires_mark_as_modified(ob); } } @@ -346,6 +368,8 @@ static void sculpt_undo_free(ListBase *lb) MEM_freeN(unode->no); if(unode->index) MEM_freeN(unode->index); + if(unode->grids) + MEM_freeN(unode->grids); } } @@ -369,9 +393,7 @@ static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node) ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); Object *ob= ss->ob; SculptUndoNode *unode; - int i, totvert, allvert, *verts; - - BLI_pbvh_node_get_verts(node, &verts, &totvert, &allvert); + int totvert, allvert, totgrid, maxgrid, gridsize, *grids; /* list is manipulated by multiple threads, so we lock */ BLI_lock_thread(LOCK_CUSTOM1); @@ -385,23 +407,46 @@ static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node) strcpy(unode->idname, ob->id.name); unode->node= node; + BLI_pbvh_node_num_verts(ss->tree, node, &totvert, &allvert); + BLI_pbvh_node_get_grids(ss->tree, node, &grids, &totgrid, &maxgrid, &gridsize); + 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*allvert, "SculptUndoNode.co"); unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no"); - unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index"); undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert); BLI_addtail(lb, unode); + if(maxgrid) { + /* multires */ + unode->maxgrid= maxgrid; + unode->totgrid= totgrid; + unode->gridsize= gridsize; + unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids"); + } + else { + /* regular mesh */ + unode->maxvert= ss->totvert; + unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index"); + } + BLI_unlock_thread(LOCK_CUSTOM1); /* copy threaded, hopefully this is the performance critical part */ - memcpy(unode->index, verts, sizeof(int)*allvert); - for(i=0; i<allvert; i++) { - copy_v3_v3(unode->co[i], ss->mvert[verts[i]].co); - VECCOPY(unode->no[i], ss->mvert[verts[i]].no); + { + PBVHVertexIter vd; + + BLI_pbvh_vertex_iter_begin(ss->tree, node, vd, PBVH_ITER_ALL) { + copy_v3_v3(unode->co[vd.i], vd.co); + if(vd.no) VECCOPY(unode->no[vd.i], vd.no) + else normal_float_to_short_v3(unode->no[vd.i], vd.fno); + if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i]; + } + BLI_pbvh_vertex_iter_end; } + + if(unode->grids) + memcpy(unode->grids, grids, sizeof(int)*totgrid); return unode; } @@ -428,57 +473,41 @@ static void sculpt_undo_push_end(SculptSession *ss) undo_paint_push_end(UNDO_PAINT_MESH); } -/************************ Looping Over Verts in a BVH Node *******************/ +void ED_sculpt_force_update(bContext *C) +{ + Object *ob= CTX_data_active_object(C); -typedef struct SculptVertexData { + if(ob && (ob->mode & OB_MODE_SCULPT)) + multires_force_update(ob); +} + +/************************ Brush Testing *******************/ + +typedef struct SculptBrushTest { 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; +} SculptBrushTest; -static void sculpt_node_verts_init(Sculpt *sd, SculptSession *ss, - PBVHNode *node, float (*origvert)[3], SculptVertexData *vd) +static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { - vd->radius_squared= ss->cache->radius*ss->cache->radius; - copy_v3_v3(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, NULL); + test->radius_squared= ss->cache->radius*ss->cache->radius; + copy_v3_v3(test->location, ss->cache->location); } -static int sculpt_node_verts_next(SculptVertexData *vd) +static int sculpt_brush_test(SculptBrushTest *test, float co[3]) { - vd->i++; - - while(vd->i < vd->totvert) { - float delta[3], dsq; + float distsq, delta[3]; - 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; - sub_v3_v3v3(delta, vd->origco, vd->location); - dsq = INPR(delta, delta); + sub_v3_v3v3(delta, co, test->location); + distsq = INPR(delta, delta); - if(dsq < vd->radius_squared) { - vd->dist = sqrt(dsq); - return 1; - } - - vd->i++; + if(distsq < test->radius_squared) { + test->dist = sqrt(distsq); + return 1; } - + return 0; } @@ -667,7 +696,6 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v) float t[3], bb_min[3], bb_max[3]; int i; - //BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); BLI_pbvh_node_get_BB(node, bb_min, bb_max); for(i = 0; i < 3; ++i) { @@ -700,12 +728,8 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va } } -static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], const short no[3]) +static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3]) { - float fno[3] = {no[0], no[1], no[2]}; - - normalize_v3(fno); - if((dot_v3v3(view_vec, fno)) > 0) { add_v3_v3v3(out, out, fno); } else { @@ -716,6 +740,7 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], cons /* 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) { + PBVH *bvh= ss->tree; StrokeCache *cache = ss->cache; const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */ float out[3] = {0.0f, 0.0f, 0.0f}; @@ -728,23 +753,39 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3] /* threaded loop over nodes */ #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; SculptUndoNode *unode; + float fno[3]; float nout[3] = {0.0f, 0.0f, 0.0f}; float nout_flip[3] = {0.0f, 0.0f, 0.0f}; // XXX push instead of get for thread safety in draw // brush .. lame, but also not harmful really unode= sculpt_undo_push_node(ss, nodes[n]); - sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); + sculpt_brush_test_init(ss, &test); - if(unode && ss->cache->original) { - while(sculpt_node_verts_next(&vd)) - add_norm_if(out_dir, nout, nout_flip, unode->no[vd.i]); + if(ss->cache->original) { + BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, unode->co[vd.i])) { + normal_short_to_float_v3(fno, unode->no[vd.i]); + add_norm_if(out_dir, nout, nout_flip, fno); + } + } + BLI_pbvh_vertex_iter_end; } else { - while(sculpt_node_verts_next(&vd)) - add_norm_if(out_dir, nout, nout_flip, ss->mvert[vd.index].no); + BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + if(vd.no) { + normal_short_to_float_v3(fno, vd.no); + add_norm_if(out_dir, nout, nout_flip, fno); + } + else + add_norm_if(out_dir, nout, nout_flip, vd.fno); + } + } + BLI_pbvh_vertex_iter_end; } { @@ -787,21 +828,25 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t /* threaded loop over nodes */ #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; sculpt_undo_push_node(ss, nodes[n]); - sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); + sculpt_brush_test_init(ss, &test); - 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}; + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + /* offset vertex */ + float fade = tex_strength(ss, brush, vd.co, test.dist); + float val[3]= {vd.co[0] + offset[0]*fade, + vd.co[1] + offset[1]*fade, + vd.co[2] + offset[2]*fade}; - sculpt_clip(sd, ss, vd.co, val); - ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE; + sculpt_clip(sd, ss, vd.co, val); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -860,23 +905,27 @@ static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int for(iteration = 0; iteration < 2; ++iteration) { #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; 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; + sculpt_brush_test_init(ss, &test); + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength; + float avg[3], val[3]; + + neighbor_average(ss, avg, vd.vert_indices[vd.i]); + val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade; + val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade; + val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade; + + sculpt_clip(sd, ss, vd.co, val); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -891,20 +940,24 @@ static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; 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_brush_test_init(ss, &test); + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength; + float val[3]= {vd.co[0]+(test.location[0]-vd.co[0])*fade, + vd.co[1]+(test.location[1]-vd.co[1])*fade, + vd.co[2]+(test.location[2]-vd.co[2])*fade}; + + sculpt_clip(sd, ss, vd.co, val); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -921,26 +974,29 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int t #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; - SculptUndoNode *unode; + PBVHVertexIter vd; + SculptBrushTest test; float (*origco)[3]; - unode= sculpt_undo_push_node(ss, nodes[n]); - origco= unode->co; - sculpt_node_verts_init(sd, ss, nodes[n], origco, &vd); - - 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; + origco= sculpt_undo_push_node(ss, nodes[n])->co; + sculpt_brush_test_init(ss, &test); + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, origco[vd.i])) { + float fade = tex_strength(ss, brush, origco[vd.i], test.dist)*bstrength; + float add[3]= {vd.co[0]+fade*grab_delta[0], + vd.co[1]+fade*grab_delta[1], + vd.co[2]+fade*grab_delta[2]}; + + sculpt_clip(sd, ss, vd.co, add); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } + } static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode) @@ -962,40 +1018,43 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; - SculptUndoNode *unode; + PBVHVertexIter vd; + SculptBrushTest test; float (*origco)[3]; - unode= sculpt_undo_push_node(ss, nodes[n]); - origco= unode->co; - sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); + origco= sculpt_undo_push_node(ss, nodes[n])->co; + sculpt_brush_test_init(ss, &test); + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength; + int index= vd.vert_indices[vd.i]; + float *disp= &ss->layer_disps[index]; + float val[3]; + + *disp+= fade; + + /* Don't let the displacement go past the limit */ + if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) + *disp = lim; + + if(ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) { + /* persistent base */ + val[0] = ss->layer_co[index][0] + (*disp)*offset[0]; + val[1] = ss->layer_co[index][1] + (*disp)*offset[1]; + val[2] = ss->layer_co[index][2] + (*disp)*offset[2]; + } + 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]; + } - 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]; - - *disp+= fade; - - /* Don't let the displacement go past the limit */ - if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim)) - *disp = lim; - - 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]; - } - 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); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } - - sculpt_clip(sd, ss, vd.co, val); - ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE; } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -1009,27 +1068,31 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; sculpt_undo_push_node(ss, nodes[n]); - sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); + sculpt_brush_test_init(ss, &test); - while(sculpt_node_verts_next(&vd)) { - const float fade = tex_strength(ss, brush, vd.co, vd.dist)*bstrength; - float add[3]; - - add[0]= vd.no[0]/32767.0f; - add[1]= vd.no[1]/32767.0f; - add[2]= vd.no[2]/32767.0f; - mul_v3_fl(add, fade * ss->cache->radius); - add[0]*= ss->cache->scale[0]; - add[1]*= ss->cache->scale[1]; - add[2]*= ss->cache->scale[2]; - add_v3_v3v3(add, add, vd.co); - - sculpt_clip(sd, ss, vd.co, add); - ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE; + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength; + float add[3]; + + add[0]= vd.no[0]/32767.0f; + add[1]= vd.no[1]/32767.0f; + add[2]= vd.no[2]/32767.0f; + mul_v3_fl(add, fade * ss->cache->radius); + add[0]*= ss->cache->scale[0]; + add[1]*= ss->cache->scale[1]; + add[2]*= ss->cache->scale[2]; + add_v3_v3v3(add, add, vd.co); + + sculpt_clip(sd, ss, vd.co, add); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -1038,36 +1101,42 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in 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]; + float outer_co[FLATTEN_SAMPLE_SIZE][3]; int i, n; for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) { - outer_index[i] = 0; + zero_v3(outer_co[i]); outer_dist[i]= -1.0f; } #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; - 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; - outer_dist[i] = vd.dist; - break; + sculpt_undo_push_node(ss, nodes[n]); + sculpt_brush_test_init(ss, &test); + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) { + if(test.dist > outer_dist[i]) { + copy_v3_v3(outer_co[i], vd.co); + outer_dist[i] = test.dist; + break; + } } } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } co[0] = co[1] = co[2] = 0.0f; for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) - add_v3_v3v3(co, co, ss->mvert[outer_index[i]].co); + if(outer_dist[i] >= 0.0f) + add_v3_v3v3(co, co, outer_co[i]); mul_v3_fl(co, 1.0f / FLATTEN_SAMPLE_SIZE); } @@ -1122,41 +1191,45 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **node #pragma omp parallel for private(n) schedule(static) for(n=0; n<totnode; n++) { - SculptVertexData vd; + PBVHVertexIter vd; + SculptBrushTest test; sculpt_undo_push_node(ss, nodes[n]); - sculpt_node_verts_init(sd, ss, nodes[n], NULL, &vd); + sculpt_brush_test_init(ss, &test); - 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); - - sub_v3_v3v3(val, intr, vd.co); - - if(clay) { - if(bstr > FLT_EPSILON) - mul_v3_fl(val, fade / bstr); + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + if(sculpt_brush_test(&test, vd.co)) { + float intr[3], val[3]; + + if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) { + const float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength; + + /* Find the intersection between squash-plane and vertex (along the area normal) */ + point_plane_project(intr, vd.co, area_normal, cntr); + + sub_v3_v3v3(val, intr, vd.co); + + if(clay) { + if(bstr > FLT_EPSILON) + mul_v3_fl(val, fade / bstr); + else + mul_v3_fl(val, fade); + /* Clay displacement */ + val[0]+=area_normal[0] * ss->cache->scale[0]*fade; + val[1]+=area_normal[1] * ss->cache->scale[1]*fade; + val[2]+=area_normal[2] * ss->cache->scale[2]*fade; + } else - mul_v3_fl(val, fade); - /* Clay displacement */ - val[0]+=area_normal[0] * ss->cache->scale[0]*fade; - val[1]+=area_normal[1] * ss->cache->scale[1]*fade; - val[2]+=area_normal[2] * ss->cache->scale[2]*fade; - } - else - mul_v3_fl(val, fabs(fade)); + mul_v3_fl(val, fabs(fade)); - add_v3_v3v3(val, val, vd.co); + add_v3_v3v3(val, val, vd.co); - sculpt_clip(sd, ss, vd.co, val); - ss->mvert[vd.index].flag |= ME_VERT_PBVH_UPDATE; + sculpt_clip(sd, ss, vd.co, val); + if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } } } + BLI_pbvh_vertex_iter_end; BLI_pbvh_node_mark_update(nodes[n]); } @@ -1312,7 +1385,7 @@ char sculpt_modifiers_active(Object *ob) ModifierData *md; for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) { - if(md->mode & eModifierMode_Realtime && md->type != eModifierType_Multires) + if(modifier_isEnabled(md, eModifierMode_Realtime) && md->type != eModifierType_Multires) return 1; } @@ -1346,9 +1419,7 @@ struct MultiresModifierData *sculpt_multires_active(Object *ob) 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); + DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, 0); SculptSession *ss = ob->sculpt; if((ss->multires = sculpt_multires_active(ob))) { @@ -1611,36 +1682,6 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct P } } -/* 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(!isect_ray_tri_v3(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; @@ -1652,53 +1693,16 @@ typedef struct { void sculpt_raycast_cb(PBVHNode *node, void *data_v) { SculptRaycastData *srd = data_v; - MVert *vert = srd->ss->mvert; - int i, totface, *faces, *face_verts; + float (*origco)[3]= NULL; if(srd->original && srd->ss->cache) { - SculptUndoNode *unode; - - unode= sculpt_undo_get_node(srd->ss, node); - - if(unode) { - /* intersect with coordinates from before we started stroke */ - BLI_pbvh_node_get_faces(node, &faces, &face_verts, &totface); - - for(i = 0; i < totface; ++i) { - MFace *f = srd->ss->mface + faces[i]; - /*if(face_verts[i*4 + 0] >= unode->totvert) abort(); - if(face_verts[i*4 + 1] >= unode->totvert) abort(); - if(face_verts[i*4 + 2] >= unode->totvert) abort(); - if(f->v4 && face_verts[i*4 + 3] >= unode->totvert) abort();*/ - - if(ray_face_intersection(srd->ray_start, srd->ray_normal, - unode->co[face_verts[i*4+0]], - unode->co[face_verts[i*4+1]], - unode->co[face_verts[i*4+2]], - f->v4? unode->co[face_verts[i*4+3]]: NULL, - &srd->dist)) { - srd->hit = faces[i]; - } - } - - return; - } + /* intersect with coordinates from before we started stroke */ + SculptUndoNode *unode= sculpt_undo_get_node(srd->ss, node); + origco= (unode)? unode->co: NULL; } - /* intersect with current coordinates */ - BLI_pbvh_node_get_faces(node, &faces, NULL, &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]; - } - } + srd->hit |= BLI_pbvh_node_raycast(srd->ss->tree, node, origco, + srd->ray_start, srd->ray_normal, &srd->dist); } /* Do a raycast in the tree to find the 3d brush location @@ -1721,7 +1725,7 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou srd.ray_start = ray_start; srd.ray_normal = ray_normal; srd.dist = FLT_MAX; - srd.hit = -1; + srd.hit = 0; srd.original = (cache)? cache->original: 0; BLI_pbvh_raycast(ss->tree, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); @@ -1730,7 +1734,7 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou mul_v3_fl(out, srd.dist); add_v3_v3v3(out, out, ray_start); - return srd.hit != -1; + return srd.hit; } /* Initialize stroke operator properties */ @@ -1794,20 +1798,25 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) /* Restore the mesh before continuing with anchored stroke */ if(brush->flag & BRUSH_ANCHORED) { - ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH); - SculptUndoNode *unode; - - /* this could benefit from multithreading... */ + PBVHNode **nodes; + int n, totnode; - for(unode = lb->first; unode; unode = unode->next) { - float (*co)[3]= unode->co; - short (*no)[3]= unode->no; - int *index= unode->index; - int totvert= unode->totvert; + BLI_pbvh_search_gather(ss->tree, NULL, NULL, &nodes, &totnode); - for(i = 0; i < totvert; ++i) { - copy_v3_v3(ss->mvert[index[i]].co, co[i]); - VECCOPY(ss->mvert[index[i]].no, no[i]); + #pragma omp parallel for private(n) schedule(static) + for(n=0; n<totnode; n++) { + SculptUndoNode *unode; + + unode= sculpt_undo_get_node(ss, nodes[n]); + if(unode) { + PBVHVertexIter vd; + + BLI_pbvh_vertex_iter_begin(ss->tree, nodes[n], vd, PBVH_ITER_UNIQUE) { + copy_v3_v3(vd.co, unode->co[vd.i]); + if(vd.no) VECCOPY(vd.no, unode->no[vd.i]) + else normal_short_to_float_v3(vd.fno, unode->no[vd.i]); + } + BLI_pbvh_vertex_iter_end; } } @@ -1831,14 +1840,8 @@ static void sculpt_flush_update(bContext *C) rcti r; int redraw = 0; - if(mmd) { - if(mmd->undo_verts && mmd->undo_verts != ss->mvert) - MEM_freeN(mmd->undo_verts); - - mmd->undo_verts = ss->mvert; - mmd->undo_verts_tot = ss->totvert; + if(mmd) multires_mark_as_modified(ob); - } BLI_pbvh_update(ss->tree, PBVH_UpdateBB, NULL); redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r); @@ -2024,10 +2027,14 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); + //MultiresModifierData *mmd = sculpt_multires_active(ob); if(ob->mode & OB_MODE_SCULPT) { multires_force_update(ob); + /*if(mmd && mmd->sculptlvl != mmd->lvl) + DAG_id_flush_update(&ob->id, OB_RECALC_DATA);*/ + /* Leave sculptmode */ ob->mode &= ~OB_MODE_SCULPT; @@ -2035,8 +2042,10 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op) } else { /* Enter sculptmode */ - ob->mode |= OB_MODE_SCULPT; + + /*if(mmd && mmd->sculptlvl != mmd->lvl) + DAG_id_flush_update(&ob->id, OB_RECALC_DATA);*/ /* Create persistent sculpt mode data */ if(!ts->sculpt) diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h index eceb0cdeca4..5531ccc813b 100644 --- a/source/blender/gpu/gpu_buffers.h +++ b/source/blender/gpu/gpu_buffers.h @@ -126,13 +126,17 @@ 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, +void *GPU_build_mesh_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, +void GPU_update_mesh_buffers(void *buffers, struct MVert *mvert, int *vert_indices, int totvert); +void *GPU_build_grid_buffers(struct DMGridData **grids, + int *grid_indices, int totgrid, int gridsize); +void GPU_update_grid_buffers(void *buffers_v, struct DMGridData **grids, + int *grid_indices, int totgrid, int gridsize); +void GPU_draw_buffers(void *buffers); void GPU_free_buffers(void *buffers); /* called before drawing */ diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index a6adf8a16a1..65b81835cf9 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -30,6 +30,7 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include <limits.h> #include <string.h> #include "GL/glew.h" @@ -388,11 +389,12 @@ typedef struct { } VertexBufferFormat; typedef struct { - unsigned int vert_buf, tri_buf; - unsigned short tot_tri; + GLuint vert_buf, index_buf; + GLenum index_type; + unsigned int tot_tri, tot_quad; } GPU_Buffers; -void GPU_update_buffers(void *buffers_v, MVert *mvert, +void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert, int *vert_indices, int totvert) { GPU_Buffers *buffers = buffers_v; @@ -414,11 +416,9 @@ void GPU_update_buffers(void *buffers_v, MVert *mvert, memcpy(out->no, v->no, sizeof(short) * 3); } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - - //printf("node updated %p\n", buffers_v); } -void *GPU_build_buffers(GHash *map, MVert *mvert, MFace *mface, +void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface, int *face_indices, int totface, int *vert_indices, int tot_uniq_verts, int totvert) @@ -428,14 +428,15 @@ void *GPU_build_buffers(GHash *map, MVert *mvert, MFace *mface, int i, j, k, tottri; buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers"); + buffers->index_type = GL_UNSIGNED_SHORT; /* 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 */ - glGenBuffersARB(1, &buffers->tri_buf); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->tri_buf); + glGenBuffersARB(1, &buffers->index_buf); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB); @@ -470,24 +471,129 @@ void *GPU_build_buffers(GHash *map, MVert *mvert, MFace *mface, /* Build VBO */ glGenBuffersARB(1, &buffers->vert_buf); - GPU_update_buffers(buffers, mvert, vert_indices, totvert); + GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert); buffers->tot_tri = tottri; return buffers; } +void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids, + int *grid_indices, int totgrid, int gridsize) +{ + GPU_Buffers *buffers = buffers_v; + DMGridData *vert_data; + int i, totvert; + + totvert= gridsize*gridsize*totgrid; + + /* Build VBO */ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, + sizeof(DMGridData) * totvert, + NULL, GL_STATIC_DRAW_ARB); + vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + + for(i = 0; i < totgrid; ++i) { + DMGridData *grid= grids[grid_indices[i]]; + memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize); + vert_data += gridsize*gridsize; + } + glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + + //printf("node updated %p\n", buffers_v); +} + +void *GPU_build_grid_buffers(DMGridData **grids, + int *grid_indices, int totgrid, int gridsize) +{ + GPU_Buffers *buffers; + int i, j, k, totquad, offset= 0; + + buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers"); + + /* Count the number of quads */ + totquad= (gridsize-1)*(gridsize-1)*totgrid; + + /* Generate index buffer object */ + glGenBuffersARB(1, &buffers->index_buf); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + + if(totquad < USHRT_MAX) { + unsigned short *quad_data; + + buffers->index_type = GL_UNSIGNED_SHORT; + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB); + + /* Fill the quad buffer */ + quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + for(i = 0; i < totgrid; ++i) { + for(j = 0; j < gridsize-1; ++j) { + for(k = 0; k < gridsize-1; ++k) { + *(quad_data++)= offset + j*gridsize + k; + *(quad_data++)= offset + (j+1)*gridsize + k; + *(quad_data++)= offset + (j+1)*gridsize + k+1; + *(quad_data++)= offset + j*gridsize + k+1; + } + } + + offset += gridsize*gridsize; + } + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + } + else { + unsigned int *quad_data; + + buffers->index_type = GL_UNSIGNED_INT; + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB); + + /* Fill the quad buffer */ + quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + for(i = 0; i < totgrid; ++i) { + for(j = 0; j < gridsize-1; ++j) { + for(k = 0; k < gridsize-1; ++k) { + *(quad_data++)= offset + j*gridsize + k; + *(quad_data++)= offset + (j+1)*gridsize + k; + *(quad_data++)= offset + (j+1)*gridsize + k+1; + *(quad_data++)= offset + j*gridsize + k+1; + } + } + + offset += gridsize*gridsize; + } + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + } + + /* Build VBO */ + glGenBuffersARB(1, &buffers->vert_buf); + GPU_update_grid_buffers(buffers, grids, grid_indices, totgrid, gridsize); + + buffers->tot_quad = totquad; + + return buffers; +} + void GPU_draw_buffers(void *buffers_v) { GPU_Buffers *buffers = buffers_v; glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->tri_buf); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + + if(buffers->tot_quad) { + glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), 0); + glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no)); - glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), 0); - glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)12); + glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0); + } + else { + glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), 0); + glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no)); - glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, GL_UNSIGNED_SHORT, 0); + glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0); + } } void GPU_free_buffers(void *buffers_v) @@ -496,7 +602,7 @@ void GPU_free_buffers(void *buffers_v) GPU_Buffers *buffers = buffers_v; glDeleteBuffersARB(1, &buffers->vert_buf); - glDeleteBuffersARB(1, &buffers->tri_buf); + glDeleteBuffersARB(1, &buffers->index_buf); MEM_freeN(buffers); } |