From 93beb0b85a4a0e301d9bfae9edee1fe7bdabba12 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Tue, 27 Oct 2009 19:53:34 +0000 Subject: Commit of the sculpt patch (#19672). Further development will be in this branch until we merge to trunk. --- source/blender/blenkernel/BKE_DerivedMesh.h | 2 +- source/blender/blenkernel/BKE_paint.h | 7 +- source/blender/blenkernel/intern/cdderivedmesh.c | 91 ++- source/blender/blenkernel/intern/object.c | 10 +- source/blender/blenkernel/intern/subsurf_ccg.c | 2 +- source/blender/blenlib/BLI_pbvh.h | 62 ++ source/blender/blenlib/CMakeLists.txt | 1 + source/blender/blenlib/SConscript | 2 +- source/blender/blenlib/intern/arithb.c | 2 +- source/blender/blenlib/intern/pbvh.c | 665 +++++++++++++++++++ source/blender/editors/include/ED_sculpt.h | 7 + source/blender/editors/include/ED_view3d.h | 6 +- source/blender/editors/object/object_modifier.c | 2 + source/blender/editors/physics/particle_edit.c | 2 +- source/blender/editors/sculpt_paint/paint_intern.h | 4 +- source/blender/editors/sculpt_paint/paint_stroke.c | 27 +- source/blender/editors/sculpt_paint/paint_vertex.c | 4 +- source/blender/editors/sculpt_paint/sculpt.c | 736 +++++++++++---------- source/blender/editors/space_view3d/drawobject.c | 34 +- source/blender/editors/space_view3d/view3d_draw.c | 39 +- source/blender/editors/space_view3d/view3d_edit.c | 47 +- .../blender/editors/space_view3d/view3d_select.c | 14 +- source/blender/editors/space_view3d/view3d_view.c | 39 ++ source/blender/gpu/gpu_buffers.h | 11 + source/blender/gpu/intern/gpu_buffers.c | 151 +++++ 25 files changed, 1486 insertions(+), 481 deletions(-) create mode 100644 source/blender/blenlib/BLI_pbvh.h create mode 100644 source/blender/blenlib/intern/pbvh.c diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 076747cb845..75d9ae7f360 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -204,7 +204,7 @@ struct DerivedMesh { * * Also called for *final* editmode DerivedMeshes */ - void (*drawFacesSolid)(DerivedMesh *dm, + void (*drawFacesSolid)(DerivedMesh *dm, void *tree, float (*partial_redraw_planes)[4], int (*setMaterial)(int, void *attribs)); /* Draw all faces diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index ba42aca1872..558659b520f 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -34,6 +34,7 @@ struct MultireModifierData; struct MVert; struct Object; struct Paint; +struct PBVH; struct Scene; struct StrokeCache; @@ -76,8 +77,10 @@ typedef struct SculptSession { /* Used temporarily per-stroke */ float *vertexcosnos; - ListBase damaged_rects; - ListBase damaged_verts; + + /* Partial redraw */ + struct PBVH *tree; + int partial_redraw; /* Used to cache the render of the active texture */ unsigned int texcache_side, *texcache, texcache_actual; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index e38bb00fe8d..6ae1057767d 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -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" @@ -360,7 +360,68 @@ 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(const int *face_indices, + const int *vert_indices, + int totface, int totvert, void *data_v) +{ + /* 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(data_v); + ++nodes_drawn; +} + +int find_all(float bb_min[3], float bb_max[3], void *data) +{ + return 1; +} + +/* 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(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, void *tree, + float (*partial_redraw_planes)[4], + int (*setMaterial)(int, void *attribs)) { CDDerivedMesh *cddm = (CDDerivedMesh*) dm; MVert *mvert = cddm->mvert; @@ -376,6 +437,32 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a glVertex3fv(mvert[index].co); \ } + if(tree) { + BLI_pbvh_search(tree, BLI_pbvh_update_search_cb, + PBVH_NodeData, NULL, NULL, + PBVH_SEARCH_UPDATE); + + if(partial_redraw_planes) { + BLI_pbvh_search(tree, planes_contain_AABB, + partial_redraw_planes, + draw_partial_cb, PBVH_DrawData, + PBVH_SEARCH_MODIFIED); + } + else { + BLI_pbvh_search(tree, find_all, NULL, + draw_partial_cb, PBVH_DrawData, + PBVH_SEARCH_NORMAL); + + } + + is_partial = !!partial_redraw_planes; + + //printf("nodes drawn=%d\n", nodes_drawn); + nodes_drawn = 0; + + return; + } + if( GPU_buffer_legacy(dm) ) { DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" ); glBegin(glmode = GL_QUADS); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ba8d41f54bb..5c3419fb488 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -72,6 +72,8 @@ #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_editVert.h" +#include "BLI_ghash.h" +#include "BLI_pbvh.h" #include "BKE_utildefines.h" @@ -228,8 +230,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); @@ -246,6 +246,12 @@ void free_sculptsession(SculptSession **ssp) if(ss->mesh_co_orig) MEM_freeN(ss->mesh_co_orig); + if(ss->tree) + BLI_pbvh_free(ss->tree); + + if(ss->face_normals) + MEM_freeN(ss->face_normals); + MEM_freeN(ss); *ssp = NULL; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 6e95fe7ebc7..7c83431ebd8 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -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, void *tree, 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 index 00000000000..edc363e65a3 --- /dev/null +++ b/source/blender/blenlib/BLI_pbvh.h @@ -0,0 +1,62 @@ +struct MFace; +struct MVert; +struct PBVH; + +/* Returns 1 if the search should continue from this node, 0 otherwise */ +typedef int (*BLI_pbvh_SearchCallback)(float bb_min[3], float bb_max[3], + void *data); + +typedef void (*BLI_pbvh_HitCallback)(const int *face_indices, + const int *vert_indices, + int totface, int totvert, void *data); +int BLI_pbvh_search_range(float bb_min[3], float bb_max[3], void *data_v); + +typedef enum { + PBVH_SEARCH_NORMAL, + + /* When the callback returns a 1 for a leaf node, that node will be + marked as modified */ + PBVH_SEARCH_MARK_MODIFIED, + + /* Update gpu data for modified nodes. Also clears the Modified flag. */ + PBVH_SEARCH_MODIFIED, + + + PBVH_SEARCH_UPDATE +} PBVH_SearchMode; + +/* Pass the node as data to the callback */ +#define PBVH_NodeData (void*)0xa +/* Pass the draw buffers as data to the callback */ +#define PBVH_DrawData (void*)0xb + +void BLI_pbvh_search(struct PBVH *bvh, BLI_pbvh_SearchCallback scb, + void *search_data, BLI_pbvh_HitCallback hcb, + void *hit_data, PBVH_SearchMode mode); + +/* 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(struct PBVH *bvh, BLI_pbvh_HitCallback cb, void *data, + float ray_start[3], float ray_normal[3]); + + +int BLI_pbvh_update_search_cb(float bb_min[3], float bb_max[3], void *data_v); + +/* Get the bounding box around all nodes that have been marked as modified. */ +void BLI_pbvh_modified_bounding_box(struct PBVH *bvh, + float bb_min[3], float bb_max[3]); +void BLI_pbvh_reset_modified_bounding_box(struct PBVH *bvh); + +/* Lock is off by default, turn on to stop redraw from clearing the modified + flag from nodes */ +void BLI_pbvh_toggle_modified_lock(struct PBVH *bvh); + + + +struct PBVH *BLI_pbvh_new(BLI_pbvh_HitCallback update_cb, void *update_cb_data); +void BLI_pbvh_build(struct PBVH *bvh, struct MFace *faces, struct MVert *verts, + int totface, int totvert); +void BLI_pbvh_free(struct PBVH *bvh); + +void BLI_pbvh_set_source(struct PBVH *bvh, struct MVert *, struct MFace *mface); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 4ed9eb4b007..00a5440bc75 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -28,6 +28,7 @@ FILE(GLOB SRC intern/*.c) SET(INC . ../makesdna ../blenkernel ../../../intern/guardedalloc ../include + ../gpu ${FREETYPE_INCLUDE_DIRS} ${ZLIB_INC} ) diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript index fc586de5085..bca9399bc27 100644 --- a/source/blender/blenlib/SConscript +++ b/source/blender/blenlib/SConscript @@ -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 = '' diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c index 6c9ae78bac4..85cd46e6f33 100644 --- a/source/blender/blenlib/intern/arithb.c +++ b/source/blender/blenlib/intern/arithb.c @@ -4324,7 +4324,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 index 00000000000..98492a8f429 --- /dev/null +++ b/source/blender/blenlib/intern/pbvh.c @@ -0,0 +1,665 @@ +#include "MEM_guardedalloc.h" + +#include "DNA_meshdata_types.h" + +#include "BLI_arithb.h" +#include "BLI_ghash.h" +#include "BLI_pbvh.h" + +#include "BKE_utildefines.h" + +#include "gpu_buffers.h" + +#include +#include +#include + +#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)); +} + +typedef enum { + PBVH_Leaf = 1, + PBVH_Modified = 2 +} NodeFlags; + +/* 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; + +typedef struct { + /* Opaque handle for drawing code */ + void *draw_buffers; + + int *vert_indices; + + /* Voxel bounds */ + BB vb; + + /* For internal nodes */ + int children_offset; + + /* Range of faces used in the node */ + int face_offset; + + unsigned short totface; + unsigned short uniq_verts, face_verts; + + char flag; +} Node; + +typedef struct PBVH { + Node *nodes; + int node_mem_count, totnode; + + int *face_indices; + int totface; + + BB modified_bb; + + BLI_pbvh_HitCallback update_cb; + void *update_cb_data; + + /* Mesh data */ + MVert *verts; + MFace *faces; + + int modified_lock; + + /* Only used during BVH build and update, + don't need to remain valid after */ + BLI_bitmap vert_bitmap; + +#ifdef PERFCNTRS + int perf_modified; +#endif +} PBVH; + +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]) +{ + if(co[0] < bb->bmin[0]) bb->bmin[0] = co[0]; + if(co[1] < bb->bmin[1]) bb->bmin[1] = co[1]; + if(co[2] < bb->bmin[2]) bb->bmin[2] = co[2]; + + if(co[0] > bb->bmax[0]) bb->bmax[0] = co[0]; + if(co[1] > bb->bmax[1]) bb->bmax[1] = co[1]; + if(co[2] > bb->bmax[2]) bb->bmax[2] = co[2]; +} + +/* 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, Node *node) +{ + BB_reset(&node->vb); + + if(node->flag & PBVH_Leaf) { + int i, j; + for(i = node->face_offset + node->totface - 1; + i >= node->face_offset; --i) { + MFace *f = bvh->faces + bvh->face_indices[i]; + const int sides = f->v4 ? 4 : 3; + + for(j = 0; j < sides; ++j) + BB_expand(&node->vb, + bvh->verts[*((&f->v1) + j)].co); + } + } + else { + BB_expand_with_bb(&node->vb, + &bvh->nodes[node->children_offset].vb); + BB_expand_with_bb(&node->vb, + &bvh->nodes[node->children_offset + 1].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) { + Node *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(Node) * bvh->node_mem_count, + "bvh nodes"); + memcpy(bvh->nodes, prev, bvh->totnode * sizeof(Node)); + 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, Node *node) +{ + GHashIterator *iter; + GHash *map; + int i, j; + + map = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp); + + node->uniq_verts = node->face_verts = 0; + + for(i = node->face_offset + node->totface - 1; + i >= node->face_offset; --i) { + MFace *f = bvh->faces + bvh->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, + bvh->face_indices + node->face_offset, + 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_offset = 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(Node) * + bvh->node_mem_count, + "bvh initial nodes"); + } + } + + bvh->faces = faces; + bvh->verts = verts; + bvh->vert_bitmap = BLI_bitmap_new(totvert); + + BB_reset(&bvh->modified_bb); + + 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(BLI_pbvh_HitCallback update_cb, void *update_cb_data) +{ + PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); + + bvh->update_cb = update_cb; + bvh->update_cb_data = update_cb_data; + + 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, Node *node, + BLI_pbvh_HitCallback cb, void *data) +{ + if(cb) { + cb(bvh->face_indices + node->face_offset, node->vert_indices, + node->totface, node->uniq_verts, data); + } +} + +static int search_sub(PBVH *bvh, Node *node, + BLI_pbvh_SearchCallback scb, void *search_data_f, + BLI_pbvh_HitCallback hcb, void *hit_data_f, + PBVH_SearchMode mode) +{ + void *search_data = search_data_f; + void *hit_data = hit_data_f; + + if(search_data_f == PBVH_NodeData) + search_data = &node->flag; + if(hit_data_f == PBVH_DrawData) + hit_data = node->draw_buffers; + + if(scb(node->vb.bmin, node->vb.bmax, search_data)) { + if(node->flag & PBVH_Leaf) { + switch(mode) { + case PBVH_SEARCH_MARK_MODIFIED: + node->flag |= PBVH_Modified; +#ifdef PERFCNTRS + ++bvh->perf_modified; +#endif + break; + case PBVH_SEARCH_MODIFIED: + if(node->flag & PBVH_Modified) { + if(bvh->update_cb) { + do_hit_callback + (bvh, node, + bvh->update_cb, + bvh->update_cb_data); + } + + GPU_update_buffers(node->draw_buffers, + bvh->verts, + node->vert_indices, + node->uniq_verts + + node->face_verts); + } + default: + break; + } + + do_hit_callback(bvh, node, hcb, hit_data); + } + else { + int mod = 0; + if(search_sub(bvh, bvh->nodes + node->children_offset, + scb, search_data_f, hcb,hit_data_f, mode)) + mod = 1; + if(search_sub(bvh, + bvh->nodes + node->children_offset + 1, + scb, search_data_f, hcb,hit_data_f, mode)) + mod = 1; + + if(mod) + node->flag |= PBVH_Modified; + } + } + + if(mode == PBVH_SEARCH_MODIFIED) { +#ifdef PERFCNTRS + if(node->flag & PBVH_Modified && node->flag & PBVH_Leaf) + --bvh->perf_modified; +#endif + if(!bvh->modified_lock) + node->flag &= ~PBVH_Modified; + } + else if(mode == PBVH_SEARCH_UPDATE) { + if(node->flag & PBVH_Modified) { + update_node_vb(bvh, node); + if(node->flag & PBVH_Leaf) + BB_expand_with_bb(&bvh->modified_bb, &node->vb); + } + } + + return node->flag & PBVH_Modified; +} + +void BLI_pbvh_search(PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data, + BLI_pbvh_HitCallback hcb, void *hit_data, + PBVH_SearchMode mode) +{ +#ifdef PERFCNTRS + printf("search mode=%s\n", + mode==PBVH_SEARCH_MARK_MODIFIED?"mark-modified": + mode==PBVH_SEARCH_MODIFIED?"modified": + mode==PBVH_SEARCH_UPDATE?"update": + mode==PBVH_SEARCH_NORMAL?"normal":"unknown-mode"); + if(mode == PBVH_SEARCH_MARK_MODIFIED) + bvh->perf_modified = 0; +#endif + + search_sub(bvh, bvh->nodes, scb, search_data, hcb, hit_data, mode); +#ifdef PERFCNTRS + printf("%d nodes marked modified\n", bvh->perf_modified); + printf("search complete\n\n"); +#endif +} + +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(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(bvh, ray_aabb_intersect, &rcd, cb, data, + PBVH_SEARCH_NORMAL); +} + +int BLI_pbvh_update_search_cb(float bb_min[3], float bb_max[3], void *data_v) +{ + int *data = data_v; + + return ((*data) & PBVH_Modified); +} + +void BLI_pbvh_modified_bounding_box(PBVH *bvh, float bb_min[3], float bb_max[3]) +{ + VecCopyf(bb_min, bvh->modified_bb.bmin); + VecCopyf(bb_max, bvh->modified_bb.bmax); +} + +void BLI_pbvh_reset_modified_bounding_box(PBVH *bvh) +{ + BB_reset(&bvh->modified_bb); +} + +void BLI_pbvh_toggle_modified_lock(PBVH *bvh) +{ + bvh->modified_lock = !bvh->modified_lock; +} diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 764efb4ef0c..12ebd74b64b 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -28,11 +28,18 @@ #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); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index be2822d8c49..d9220387073 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -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); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 1b0dc95480a..39a8a026afb 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -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; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index ee1a21db7e5..0681cf0fe0d 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -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); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b5748d7bc88..0689e8e63d7 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,11 +43,13 @@ struct ARegion; struct VPaint; /* 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); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 6e256bee7f2..f8ffaacc0b7 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -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; @@ -118,12 +119,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 +210,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,7 +232,6 @@ 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]; @@ -246,20 +251,20 @@ 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); + //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); + ;//ED_region_tag_redraw(ar); } else paint_brush_stroke_add_step(C, op, event, mouse); } else - ED_region_tag_redraw(ar); + ;//ED_region_tag_redraw(ar); } /* TODO: fix hardcoded event here */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 1dac98780da..c4379ac187b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1493,7 +1493,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); @@ -1792,7 +1792,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); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c4c7f436f12..b4b002283fd 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -35,6 +35,8 @@ #include "BLI_arithb.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" +#include "BLI_ghash.h" +#include "BLI_pbvh.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" @@ -52,6 +54,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 +134,6 @@ typedef struct StrokeCache { int flag; float clip_tolerance[3]; float initial_mouse[2]; - float depth; /* Variants */ float radius; @@ -147,6 +149,10 @@ 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 */ @@ -159,20 +165,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 +181,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 +189,120 @@ static void project(bglMats *mats, const float v[3], short p[2]) p[0]= f[0]; p[1]= f[1]; } +*/ + +/*** BVH Tree ***/ + +/* Updates all the face and vertex normals in a node + + Note: the correctness of some vertex normals will be a little + off, not sure if this will be noticeable or not */ +static void sculpt_update_normals(const int *face_indices, + const int *vert_indices, + int totface, int totvert, void *data) +{ + SculptSession *ss = data; + int i; + + /* Update face normals */ + for(i = 0; i < totface; ++i) { + MFace *f = ss->mface + face_indices[i]; + float *fn = ss->face_normals + face_indices[i] * 3; + + if(f->v4) + CalcNormFloat4(ss->mvert[f->v1].co, ss->mvert[f->v2].co, + ss->mvert[f->v3].co, ss->mvert[f->v4].co, fn); + else + CalcNormFloat(ss->mvert[f->v1].co, ss->mvert[f->v2].co, + ss->mvert[f->v3].co, fn); + } + + /* Update vertex normals */ + for(i = 0; i < totvert; ++i) { + const int v = vert_indices[i]; + float no[3] = {0,0,0}; + IndexNode *face; + + for(face = ss->fmap[v].first; face; face = face->next) + VecAddf(no, no, ss->face_normals + face->index*3); + + Normalize(no); + + ss->mvert[v].no[0] = no[0] * 32767; + ss->mvert[v].no[1] = no[1] * 32767; + ss->mvert[v].no[2] = no[2] * 32767; + } +} + +static void sculpt_rebuild_tree(SculptSession *ss) +{ + if(ss->tree) + BLI_pbvh_free(ss->tree); + + ss->tree = BLI_pbvh_new(sculpt_update_normals, ss); + BLI_pbvh_build(ss->tree, ss->mface, ss->mvert, ss->totface, + ss->totvert); +} + +/* 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_modified_bounding_box(ob->sculpt->tree, bb_min, bb_max); + + rect->xmin = rect->ymin = INT_MAX; + rect->xmax = rect->ymax = INT_MIN; + + 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); + BLI_pbvh_reset_modified_bounding_box(ob->sculpt->tree); + + + rect.xmin += 2; + rect.xmax -= 2; + rect.ymin += 2; + rect.ymax -= 2; + + view3d_calculate_clipping(bb, planes, &mats, &rect); + + for(i = 0; i < 16; ++i) + ((float*)planes)[i] = -((float*)planes)[i]; + + MEM_freeN(bb); +} + /* ===== Sculpting ===== * @@ -306,12 +412,9 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_ { 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; @@ -319,20 +422,10 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_ 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; - } - } - sculpt_clip(sd, ss, co, val); node= node->next; } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } /* For the smooth brush, uses the neighboring vertices around vert to calculate @@ -382,7 +475,6 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert) static void do_smooth_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; int i; for(i = 0; i < 2; ++i) { @@ -396,24 +488,15 @@ static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active val[2] = co[2]+(avg[2]-co[2])*node->Fade; 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; - } - } + 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; @@ -421,19 +504,9 @@ static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_ 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; - } - } - 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) @@ -441,7 +514,6 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss) 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); @@ -452,28 +524,16 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss) 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) @@ -481,7 +541,6 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active 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; @@ -497,27 +556,16 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active 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; @@ -532,20 +580,10 @@ static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *activ add[2]*= ss->cache->scale[2]; VecAddf(add, add, co); - 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_clip(s, ss, co, add); node= node->next; } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3]) @@ -606,7 +644,6 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase 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); @@ -619,8 +656,6 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase flip = bstr < 0; } - buffer = ss->drawobject!=0?(float *)GPU_buffer_lock( ss->drawobject->vertices ):0; - while(node){ float *co= ss->mvert[node->Index].co; float intr[3], val[3]; @@ -646,21 +681,12 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase 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); } node= node->next; } - if( buffer != 0 ) - GPU_buffer_unlock( ss->drawobject->vertices ); } /* Uses symm to selectively flip any axis of a coordinate. */ @@ -718,9 +744,8 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float } /* Return a multiplier for brush strength on a particular vertex. */ -static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const float len) +static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len) { - Brush *br = paint_brush(&sd->paint); MTex *tex = NULL; float avg= 1; @@ -795,111 +820,124 @@ static float tex_strength(Sculpt *sd, SculptSession *ss, float *point, const flo return avg; } -/* 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) +typedef struct { + SculptSession *ss; + float radius_squared; + ListBase *active_verts; +} SculptSearchSphereData; + +/* Test AABB against sphere */ +static int sculpt_search_sphere_cb(float bb_min[3], float bb_max[3], + void *data_v) { - 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; + SculptSearchSphereData *data = data_v; + float *center = data->ss->cache->location, nearest[3]; + float t[3]; + int i; - /* 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; + 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); - BLI_addtail(&ss->damaged_rects, rn); + return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared; +} - /* Update insides */ - for(i=0; itotvert; ++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; - } +static void sculpt_brush_hit_cb(const int *face_indices, + const int *vert_indices, + int totface, int totvert, void *data_v) +{ + SculptSearchSphereData *data = data_v; + int i; + + /* XXX: for now we still make an active vert list, + can be fixed later */ + + for(i = 0; i < totvert; ++i) { + int v = vert_indices[i]; + float delta[3], dsq; + + VecSubf(delta, data->ss->mvert[v].co, + data->ss->cache->location); + dsq = Inpf(delta, delta); + + if(dsq < data->radius_squared) { + ActiveData *adata = + (ActiveData*)MEM_mallocN(sizeof(ActiveData), + "ActiveData"); + adata->Index = v; + adata->dist = sqrt(dsq); + BLI_addtail(data->active_verts, adata); } - // XXX: remember to fix this! - // temporary pass - ss->projverts[i].inside = 1; } } static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache) { Brush *brush = paint_brush(&sd->paint); - float av_dist; - ListBase active_verts={0,0}; + ListBase local_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); */ + ListBase *active_verts = &local_active_verts; const float bstrength= brush_strength(sd, cache); - KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */ - Brush *b = brush; - int i; - - sculpt_add_damaged_rect(ss); + //KeyBlock *keyblock= NULL; /*XXX: ob_get_keyblock(OBACT); */ + ActiveData *adata; + + /* For grab brush, only find active vertices once */ + if(brush->sculpt_tool == SCULPT_TOOL_GRAB) + active_verts = grab_active_verts; /* 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; itotvert; ++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); - } - } - } + area of influence */ + if(brush->sculpt_tool != SCULPT_TOOL_GRAB || cache->first_time) { + SculptSearchSphereData data; + data.ss = ss; + data.radius_squared = ss->cache->radius * ss->cache->radius; + data.active_verts = active_verts; + BLI_pbvh_search(ss->tree, sculpt_search_sphere_cb, &data, + sculpt_brush_hit_cb, &data, + PBVH_SEARCH_MARK_MODIFIED); + + /* Update brush strength for each vertex */ + for(adata = active_verts->first; adata; adata = adata->next) + adata->Fade = tex_strength(ss, brush, ss->mvert[adata->Index].co, adata->dist) * bstrength; } /* 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(active_verts->first) { /* 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, active_verts); break; case SCULPT_TOOL_SMOOTH: - do_smooth_brush(sd, ss, &active_verts); + do_smooth_brush(sd, ss, active_verts); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, ss, &active_verts); + do_pinch_brush(sd, ss, active_verts); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, ss, &active_verts); + do_inflate_brush(sd, ss, active_verts); break; case SCULPT_TOOL_GRAB: do_grab_brush(sd, ss); break; case SCULPT_TOOL_LAYER: - do_layer_brush(sd, ss, &active_verts); + do_layer_brush(sd, ss, active_verts); break; case SCULPT_TOOL_FLATTEN: - do_flatten_clay_brush(sd, ss, &active_verts, 0); + do_flatten_clay_brush(sd, ss, active_verts, 0); break; case SCULPT_TOOL_CLAY: - do_flatten_clay_brush(sd, ss, &active_verts, 1); + do_flatten_clay_brush(sd, ss, active_verts, 1); } +#if 0 /* Copy the modified vertices from mesh to the active key */ if(keyblock && !ss->multires) { float *co= keyblock->data; @@ -919,9 +957,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 + + BLI_freelistN(&local_active_verts); + + } } /* Flip all the editdata across the axis/axes specified by symm. Used to @@ -955,110 +997,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 +1014,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; itotvert; ++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) { @@ -1132,10 +1056,9 @@ static void sculpt_update_mesh_elements(bContext *C) Object *ob = CTX_data_active_object(C); 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); + 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); @@ -1148,23 +1071,20 @@ static void sculpt_update_mesh_elements(bContext *C) ss->totface = me->totface; ss->mvert = me->mvert; ss->mface = me->mface; - ss->face_normals = NULL; - } - if( GPU_buffer_legacy( dm ) ) { - ss->drawobject = 0; - } - else { - ss->drawobject = dm->drawObject; + if(!ss->face_normals) + ss->face_normals = MEM_callocN(sizeof(float) * 3 * me->totface, "sculpt face normals"); } - if(ss->totvert != oldtotvert) { - if(ss->projverts) MEM_freeN(ss->projverts); - ss->projverts = NULL; + if(ss->tree) + BLI_pbvh_set_source(ss->tree, ss->mvert, ss->mface); + if(ss->totvert != oldtotvert) { 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; + + sculpt_rebuild_tree(ss); } } @@ -1251,15 +1171,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) @@ -1290,15 +1208,17 @@ 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->vc = vc; + cache->brush = brush; + cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats"); - view3d_get_transformation(vc, vc->obact, cache->mats); + view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats); sculpt_update_mesh_elements(C); @@ -1338,14 +1258,14 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte } } - 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); + //view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); + cache->initial_radius = unproject_brush_radius(vc, cache->true_location, 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); @@ -1375,7 +1295,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,13 +1319,103 @@ 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(const int *face_indices, + const int *vert_indices, + int totface, int totvert, void *data_v) +{ + SculptRaycastData *srd = data_v; + MVert *vert = srd->ss->mvert; + int i; + + for(i = 0; i < totface; ++i) { + MFace *f = srd->ss->mface + face_indices[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 = face_indices[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) { @@ -1442,9 +1453,6 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE 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); } @@ -1467,30 +1475,16 @@ 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(ss->drawobject) - buffer= (float *)GPU_buffer_lock(ss->drawobject->normals); - 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 +1497,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 +1515,46 @@ static void sculpt_flush_update(bContext *C) multires_mark_as_modified(ob); } - ED_region_tag_redraw(ar); + redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r); + + if(!redraw) { + BLI_pbvh_search(ss->tree, BLI_pbvh_update_search_cb, + PBVH_NodeData, NULL, NULL, + PBVH_SEARCH_UPDATE); + + 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; + + if(paint_brush(&CTX_data_tool_settings(C)->sculpt->paint)->sculpt_tool == SCULPT_TOOL_GRAB) + BLI_pbvh_toggle_modified_lock(ss->tree); + + 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); return 1; } @@ -1556,13 +1567,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,9 +1581,11 @@ 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; + + if(paint_brush(&CTX_data_tool_settings(C)->sculpt->paint)->sculpt_tool == SCULPT_TOOL_GRAB) + BLI_pbvh_toggle_modified_lock(ss->tree); - request_depth_update(paint_stroke_view_context(stroke)->rv3d); sculpt_cache_free(ss->cache); ss->cache = NULL; sculpt_undo_push(C, sd); @@ -1584,7 +1596,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,12 +1614,12 @@ 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); @@ -1649,9 +1662,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) ****/ @@ -1688,6 +1698,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); +} + static int sculpt_toggle_mode(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); @@ -1713,7 +1730,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); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 22fd77afd88..5d7e5932bd8 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -107,6 +107,7 @@ #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, 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, ob->sculpt->tree, fpl, GPU_enable_material); + } + else + dm->drawFacesSolid(dm, NULL, 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; @@ -2970,7 +2986,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 +5582,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; @@ -6260,7 +6276,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, NULL, GPU_enable_material); GPU_end_object_materials(); } else if(edm) diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 15e41a66981..05de5ce1169 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -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; @@ -2038,7 +2007,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); @@ -2051,8 +2020,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); } @@ -2067,8 +2034,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); } @@ -2090,8 +2055,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(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 51f257da432..45aa2434897 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -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; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index b13d83c0157..1f7d50e00ed 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -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 ********************* */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 12654bdac14..77833ceb5c5 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -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]) { diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h index 662912f9c19..eceb0cdeca4 100644 --- a/source/blender/gpu/gpu_buffers.h +++ b/source/blender/gpu/gpu_buffers.h @@ -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 ); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 9e164f46e4c..14f2c1b6d5b 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -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; -- cgit v1.2.3