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.
This commit is contained in:
2012-12-30 18:24:54 +00:00
parent 2e9cb31c02
commit d383c32413
4 changed files with 265 additions and 1 deletions

View File

@@ -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;