diff options
author | Nicholas Bishop <nicholasbishop@gmail.com> | 2012-12-30 22:24:54 +0400 |
---|---|---|
committer | Nicholas Bishop <nicholasbishop@gmail.com> | 2012-12-30 22:24:54 +0400 |
commit | d383c324131f6b295512403c367dc3b932a1de90 (patch) | |
tree | 5ed5df8f5511bb939eeef789ceb7bdc75de6d469 | |
parent | 2e9cb31c02378fd5b9b3f26f6f26501d1aa999a2 (diff) |
Add GPU_buffers support for drawing dynamic topology nodes
The GPU interface for PBVH drawing gets a new pair of build/update
buffers functions for drawing BMFaces and BMVerts.
TODO: the diffuse color is hardcoded to 0.8 gray rather than using
material color.
TODO: only VBO drawing is implemented, no immediate mode.
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/gpu/GPU_buffers.h | 11 | ||||
-rw-r--r-- | source/blender/gpu/SConscript | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_buffers.c | 252 |
4 files changed, 265 insertions, 1 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 9ce42d9e0bb..6abc41759e7 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../blenkernel ../blenlib ../blenloader + ../bmesh ../imbuf ../makesdna ../makesrna diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 36fbd818f11..70ca44c2a3a 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -39,12 +39,15 @@ #define DEBUG_VBO(X) #endif +struct BMesh; struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; struct DerivedMesh; +struct GHash; struct GPUVertPointLink; +struct PBVH; typedef struct GPUBuffer { int size; /* in bytes */ @@ -168,6 +171,14 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert, GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize); +GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading); + +void GPU_update_bmesh_buffers(GPU_Buffers *buffers, + struct BMesh *bm, + struct GHash *bm_faces, + struct GHash *bm_unique_verts, + struct GHash *bm_other_verts); + void GPU_update_grid_buffers(GPU_Buffers *buffers, struct CCGElem **grids, const struct DMFlagMat *grid_flag_mats, int *grid_indices, int totgrid, const struct CCGKey *key, diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index aeb7edc2c56..f7db3dfeaa0 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -33,7 +33,7 @@ sources += env.Glob('shaders/*.c') defs = [ 'GLEW_STATIC' ] incs = '../blenlib ../blenkernel ../makesdna ../makesrna ../include ../blenloader ../nodes ../nodes/intern' -incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf .' +incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf ../bmesh .' if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index daf97c4841f..ba090137118 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -57,6 +57,8 @@ #include "GPU_buffers.h" #include "GPU_draw.h" +#include "bmesh.h" + typedef enum { GPU_BUFFER_VERTEX_STATE = 1, GPU_BUFFER_NORMAL_STATE = 2, @@ -1269,6 +1271,8 @@ struct GPU_Buffers { int totgrid; int has_hidden; + int use_bmesh; + unsigned int tot_tri, tot_quad; /* The PBVH ensures that either all faces in the node are @@ -1862,6 +1866,254 @@ GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid, #undef FILL_QUAD_BUFFER +/* Output a BMVert into a VertexBufferFormat array + * + * The vertex is skipped if hidden, otherwise the output goes into + * index '*v_index' in the 'vert_data' array and '*v_index' is + * incremented. + */ +static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, BMesh *bm, + VertexBufferFormat *vert_data, + int *v_index, + const float fno[3], + const float *fmask) +{ + VertexBufferFormat *vd = &vert_data[*v_index]; + float *mask; + + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + /* TODO: should use material color */ + float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; + + /* Set coord, normal, and mask */ + copy_v3_v3(vd->co, v->co); + normal_float_to_short_v3(vd->no, fno ? fno : v->no); + mask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK); + gpu_color_from_mask_copy(fmask ? *fmask : *mask, + diffuse_color, + vd->color); + + + /* Assign index for use in the triangle index buffer */ + BM_elem_index_set(v, (*v_index)); /* set_dirty! */ + + (*v_index)++; + } +} + +/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ +static int gpu_bmesh_vert_visible_count(GHash *bm_unique_verts, + GHash *bm_other_verts) +{ + GHashIterator gh_iter; + int totvert = 0; + + GHASH_ITER (gh_iter, bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + totvert++; + } + GHASH_ITER (gh_iter, bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + totvert++; + } + + return totvert; +} + +/* Return TRUE if all vertices in the face are visible, FALSE otherwise */ +static int gpu_bmesh_face_visible(BMFace *f) +{ + BMIter bm_iter; + BMVert *v; + + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + return FALSE; + } + + return TRUE; +} + +/* Return the total number of visible faces */ +static int gpu_bmesh_face_visible_count(GHash *bm_faces) +{ + GHashIterator gh_iter; + int totface = 0; + + GHASH_ITER (gh_iter, bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + if (gpu_bmesh_face_visible(f)) + totface++; + } + + return totface; +} + +/* Creates a vertex buffer (coordinate, normal, color) and, if smooth + shading, an element index buffer. */ +void GPU_update_bmesh_buffers(GPU_Buffers *buffers, + BMesh *bm, + GHash *bm_faces, + GHash *bm_unique_verts, + GHash *bm_other_verts) +{ + VertexBufferFormat *vert_data; + void *tri_data; + int tottri, totvert, maxvert = 0; + + if (!buffers->vert_buf || (buffers->smooth && !buffers->index_buf)) + return; + + /* Count visible triangles */ + tottri = gpu_bmesh_face_visible_count(bm_faces); + + if (buffers->smooth) { + /* Count visible vertices */ + totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts); + } + else + totvert = tottri * 3; + + /* Initialize vertex buffer */ + glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, + sizeof(VertexBufferFormat) * totvert, + NULL, GL_STATIC_DRAW_ARB); + + /* Fill vertex buffer */ + vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (vert_data) { + GHashIterator gh_iter; + int v_index = 0; + + if (buffers->smooth) { + /* Vertices get an index assigned for use in the triangle + index buffer */ + bm->elem_index_dirty |= BM_VERT; + + GHASH_ITER (gh_iter, bm_unique_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + bm, vert_data, &v_index, NULL, NULL); + } + + GHASH_ITER (gh_iter, bm_other_verts) { + gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter), + bm, vert_data, &v_index, NULL, NULL); + } + + maxvert = v_index; + } + else { + GHASH_ITER (gh_iter, bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + BLI_assert(f->len == 3); + + if (gpu_bmesh_face_visible(f)) { + BMVert *v[3]; + float fmask = 0; + int i; + + BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3); + + /* Average mask value */ + for (i = 0; i < 3; i++) { + fmask += *((float*)CustomData_bmesh_get(&bm->vdata, + v[i]->head.data, + CD_PAINT_MASK)); + } + fmask /= 3.0f; + + for (i = 0; i < 3; i++) { + gpu_bmesh_vert_to_buffer_copy(v[i], bm, vert_data, + &v_index, f->no, &fmask); + } + } + } + + buffers->tot_tri = tottri; + } + + glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); + } + else { + /* Memory map failed */ + glDeleteBuffersARB(1, &buffers->vert_buf); + buffers->vert_buf = 0; + return; + } + + if (buffers->smooth) { + const int use_short = (maxvert < USHRT_MAX); + + /* Initialize triangle index buffer */ + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + (use_short ? + sizeof(unsigned short) : + sizeof(unsigned int)) * 3 * tottri, + NULL, GL_STATIC_DRAW_ARB); + + /* Fill triangle index buffer */ + tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + if (tri_data) { + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, bm_faces) { + BMIter bm_iter; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMVert *v; + + if (gpu_bmesh_face_visible(f)) { + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (use_short) { + unsigned short *elem = tri_data; + (*elem) = BM_elem_index_get(v); + elem++; + tri_data = elem; + } + else { + unsigned int *elem = tri_data; + (*elem) = BM_elem_index_get(v); + elem++; + tri_data = elem; + } + } + } + } + + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); + + buffers->tot_tri = tottri; + buffers->index_type = (use_short ? + GL_UNSIGNED_SHORT : + GL_UNSIGNED_INT); + } + else { + /* Memory map failed */ + glDeleteBuffersARB(1, &buffers->index_buf); + buffers->index_buf = 0; + } + } +} + +GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading) +{ + GPU_Buffers *buffers; + + buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers"); + if (smooth_shading) + glGenBuffersARB(1, &buffers->index_buf); + glGenBuffersARB(1, &buffers->vert_buf); + buffers->use_bmesh = TRUE; + buffers->smooth = smooth_shading; + + return buffers; +} + static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers) { const MVert *mvert = buffers->mvert; |