diff options
-rw-r--r-- | source/blender/blenkernel/intern/mesh_render.c | 238 |
1 files changed, 167 insertions, 71 deletions
diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c index b1c7a5f2791..c442cf0bc73 100644 --- a/source/blender/blenkernel/intern/mesh_render.c +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -134,6 +134,36 @@ enum { MR_DATATYPE_OVERLAY = 1 << 5, }; +/** + * These functions look like they would be slow but they will typically return true on the first iteration. + * Only false when all attached elements are hidden. + */ +static bool bm_vert_has_visible_edge(const BMVert *v) +{ + const BMEdge *e_iter, *e_first; + + e_iter = e_first = v->e; + do { + if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) { + return true; + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first); + return false; +} + +static bool bm_edge_has_visible_face(const BMEdge *e) +{ + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + return false; +} + + static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) { MeshRenderData *mrdata = MEM_callocN(sizeof(*mrdata), __func__); @@ -186,9 +216,11 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) BMVert **vtable = bm->vtable; for (int i = 0; i < bm->totvert; i++) { const BMVert *v = vtable[i]; - /* Loose vert */ - if (v->e == NULL) { - lverts[mrdata->totlvert++] = i; + if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + /* Loose vert */ + if (v->e == NULL || !bm_vert_has_visible_edge(v)) { + lverts[mrdata->totlvert++] = i; + } } } } @@ -198,9 +230,11 @@ static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) BMEdge **etable = bm->etable; for (int i = 0; i < bm->totedge; i++) { const BMEdge *e = etable[i]; - /* Loose edge */ - if (e->l == NULL) { - ledges[mrdata->totledge++] = i; + if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + /* Loose edge */ + if (e->l == NULL || !bm_edge_has_visible_face(e)) { + ledges[mrdata->totledge++] = i; + } } } } @@ -334,7 +368,7 @@ static short *mesh_render_data_vert_nor(const MeshRenderData *mrdata, const int } } -static void mesh_render_data_edge_verts_indices_get( +static bool mesh_render_data_edge_verts_indices_get( const MeshRenderData *mrdata, const int edge_idx, int r_vert_idx[2]) { @@ -342,6 +376,9 @@ static void mesh_render_data_edge_verts_indices_get( if (mrdata->edit_bmesh) { const BMEdge *bm_edge = BM_edge_at_index(mrdata->edit_bmesh->bm, edge_idx); + if (BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN)) { + return false; + } r_vert_idx[0] = BM_elem_index_get(bm_edge->v1); r_vert_idx[1] = BM_elem_index_get(bm_edge->v2); } @@ -350,9 +387,10 @@ static void mesh_render_data_edge_verts_indices_get( r_vert_idx[0] = me->v1; r_vert_idx[1] = me->v2; } + return true; } -static void mesh_render_data_pnors_pcenter_select_get( +static bool mesh_render_data_pnors_pcenter_select_get( MeshRenderData *mrdata, const int poly, float r_pnors[3], float r_center[3], bool *r_selected) { @@ -360,6 +398,9 @@ static void mesh_render_data_pnors_pcenter_select_get( if (mrdata->edit_bmesh) { const BMFace *bf = BM_face_at_index(mrdata->edit_bmesh->bm, poly); + if (BM_elem_flag_test(bf, BM_ELEM_HIDDEN)) { + return false; + } BM_face_calc_center_mean(bf, r_center); BM_face_calc_normal(bf, r_pnors); *r_selected = (BM_elem_flag_test(bf, BM_ELEM_SELECT) != 0) ? true : false; @@ -374,23 +415,31 @@ static void mesh_render_data_pnors_pcenter_select_get( *r_selected = false; /* No selection if not in edit mode */ } + + return true; } static bool mesh_render_data_edge_vcos_manifold_pnors( MeshRenderData *mrdata, const int edge_index, - float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2) + float **r_vco1, float **r_vco2, float **r_pnor1, float **r_pnor2, bool *r_is_manifold) { BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); if (mrdata->edit_bmesh) { BMesh *bm = mrdata->edit_bmesh->bm; BMEdge *bm_edge = BM_edge_at_index(bm, edge_index); + if (BM_elem_flag_test(bm_edge, BM_ELEM_HIDDEN)) { + return false; + } *r_vco1 = bm_edge->v1->co; *r_vco2 = bm_edge->v2->co; if (BM_edge_is_manifold(bm_edge)) { *r_pnor1 = bm_edge->l->f->no; *r_pnor2 = bm_edge->l->radial_next->f->no; - return true; + *r_is_manifold = true; + } + else { + *r_is_manifold = false; } } else { @@ -432,14 +481,17 @@ static bool mesh_render_data_edge_vcos_manifold_pnors( if (eap[edge_index].count == 2) { *r_pnor1 = pnors[eap[edge_index].face_index[0]]; *r_pnor2 = pnors[eap[edge_index].face_index[1]]; - return true; + *r_is_manifold = true; + } + else { + *r_is_manifold = false; } } - return false; + return true; } -static void mesh_render_data_looptri_vert_indices_get( +static bool mesh_render_data_looptri_vert_indices_get( const MeshRenderData *mrdata, const int tri_idx, int r_vert_idx[3]) { @@ -447,6 +499,9 @@ static void mesh_render_data_looptri_vert_indices_get( if (mrdata->edit_bmesh) { const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } r_vert_idx[0] = BM_elem_index_get(bm_looptri[0]->v); r_vert_idx[1] = BM_elem_index_get(bm_looptri[1]->v); r_vert_idx[2] = BM_elem_index_get(bm_looptri[2]->v); @@ -458,13 +513,15 @@ static void mesh_render_data_looptri_vert_indices_get( r_vert_idx[1] = l_tri[1]->v; r_vert_idx[2] = l_tri[2]->v; } + + return true; } /** * Version of #mesh_render_data_looptri_verts_indices_get that assigns * edge indices too \a r_edges_idx (-1 for non-existant edges). */ -static void mesh_render_data_looptri_vert_edge_indices_get( +static bool mesh_render_data_looptri_vert_edge_indices_get( const MeshRenderData *mrdata, const int tri_idx, int r_vert_idx[3], int r_edges_idx[3]) { @@ -476,6 +533,10 @@ static void mesh_render_data_looptri_vert_edge_indices_get( if (mrdata->edit_bmesh) { const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx]; + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + /* assign 'r_edges_idx' & 'r_vert_idx' */ int j, j_next; for (j = 2, j_next = 0; j_next < 3; j = j_next++) { @@ -516,16 +577,23 @@ static void mesh_render_data_looptri_vert_edge_indices_get( r_vert_idx[j] = e_pair_loop[0]; /* l->v */ } } + + return true; } static bool mesh_render_data_looptri_cos_nors_smooth_get( MeshRenderData *mrdata, const int tri_idx, - float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3]) + float *(*r_vert_cos)[3], short **r_tri_nor, short *(*r_vert_nors)[3], bool *r_is_smooth) { BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); if (mrdata->edit_bmesh) { const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx]; + + if (BM_elem_flag_test(bm_looptri[0]->f, BM_ELEM_HIDDEN)) { + return false; + } + short (*pnors_short)[3] = mrdata->poly_normals_short; short (*vnors_short)[3] = mrdata->vert_normals_short; @@ -560,7 +628,7 @@ static bool mesh_render_data_looptri_cos_nors_smooth_get( (*r_vert_nors)[1] = vnors_short[BM_elem_index_get(bm_looptri[1]->v)]; (*r_vert_nors)[2] = vnors_short[BM_elem_index_get(bm_looptri[2]->v)]; - return BM_elem_flag_test_bool(bm_looptri[0]->f, BM_ELEM_SMOOTH); + *r_is_smooth = BM_elem_flag_test_bool(bm_looptri[0]->f, BM_ELEM_SMOOTH); } else { const MLoopTri *mlt = &mrdata->mlooptri[tri_idx]; @@ -590,8 +658,9 @@ static bool mesh_render_data_looptri_cos_nors_smooth_get( (*r_vert_nors)[1] = mrdata->mvert[mrdata->mloop[mlt->tri[1]].v].no; (*r_vert_nors)[2] = mrdata->mvert[mrdata->mloop[mlt->tri[2]].v].no; - return (mrdata->mpoly[mlt->poly].flag & ME_SMOOTH) != 0; + *r_is_smooth = (mrdata->mpoly[mlt->poly].flag & ME_SMOOTH) != 0; } + return true; } /* First 2 bytes are bit flags @@ -942,23 +1011,30 @@ static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *mrdata for (int i = 0; i < tottri; i++) { float *tri_vert_cos[3]; short *tri_nor, *tri_vert_nors[3]; + bool is_smooth; - const bool is_smooth = mesh_render_data_looptri_cos_nors_smooth_get(mrdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors); + if (mesh_render_data_looptri_cos_nors_smooth_get( + mrdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors, &is_smooth)) + { + if (is_smooth) { + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[0]); + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[1]); + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[2]); + } + else { + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + } - if (is_smooth) { - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[0]); - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[1]); - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[2]); - } - else { - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); - VertexBuffer_set_attrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[0]); + VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[1]); + VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[2]); } + } - VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[0]); - VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[1]); - VertexBuffer_set_attrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[2]); + if (vidx != tottri * 3) { + VertexBuffer_resize_data(cache->pos_with_normals, vidx); } } return cache->pos_with_normals; @@ -1002,8 +1078,9 @@ static ElementList *mesh_batch_cache_get_edges_in_order(MeshRenderData *mrdata, ElementListBuilder_init(&elb, PRIM_LINES, edge_ct, vertex_ct); for (int i = 0; i < edge_ct; ++i) { int vert_idx[2]; - mesh_render_data_edge_verts_indices_get(mrdata, i, vert_idx); - add_line_vertices(&elb, vert_idx[0], vert_idx[1]); + if (mesh_render_data_edge_verts_indices_get(mrdata, i, vert_idx)) { + add_line_vertices(&elb, vert_idx[0], vert_idx[1]); + } } cache->edges_in_order = ElementList_build(&elb); } @@ -1023,9 +1100,9 @@ static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *mrda ElementListBuilder_init(&elb, PRIM_TRIANGLES, tri_ct, vertex_ct); for (int i = 0; i < tri_ct; ++i) { int tri_vert_idx[3]; - mesh_render_data_looptri_vert_indices_get(mrdata, i, tri_vert_idx); - - add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]); + if (mesh_render_data_looptri_vert_indices_get(mrdata, i, tri_vert_idx)) { + add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]); + } } cache->triangles_in_order = ElementList_build(&elb); } @@ -1140,38 +1217,47 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) const int edge_ct = mesh_render_data_edges_num_get(mrdata); const int vertex_ct = edge_ct * 2; /* these are PRIM_LINE verts, not mesh verts */ + int gpu_edge_idx = 0; VertexBuffer_allocate_data(vbo, vertex_ct); for (int i = 0; i < edge_ct; ++i) { float *vcos1, *vcos2; float *pnor1 = NULL, *pnor2 = NULL; - const bool is_manifold = mesh_render_data_edge_vcos_manifold_pnors(mrdata, i, &vcos1, &vcos2, &pnor1, &pnor2); + bool is_manifold; + + if (mesh_render_data_edge_vcos_manifold_pnors(mrdata, i, &vcos1, &vcos2, &pnor1, &pnor2, &is_manifold)) { #if USE_10_10_10 - PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; - PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; + PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; + PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; - if (is_manifold) { - n1value = convert_i10_v3(pnor1); - n2value = convert_i10_v3(pnor2); - } + if (is_manifold) { + n1value = convert_i10_v3(pnor1); + n2value = convert_i10_v3(pnor2); + } - const PackedNormal *n1 = &n1value; - const PackedNormal *n2 = &n2value; + const PackedNormal *n1 = &n1value; + const PackedNormal *n2 = &n2value; #else - const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; - const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; + const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; + const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; - const float *n1 = (is_manifold) ? pnor1 : dummy1; - const float *n2 = (is_manifold) ? pnor2 : dummy2; + const float *n1 = (is_manifold) ? pnor1 : dummy1; + const float *n2 = (is_manifold) ? pnor2 : dummy2; #endif - VertexBuffer_set_attrib(vbo, pos_id, 2 * i, vcos1); - VertexBuffer_set_attrib(vbo, n1_id, 2 * i, n1); - VertexBuffer_set_attrib(vbo, n2_id, 2 * i, n2); + VertexBuffer_set_attrib(vbo, pos_id, 2 * i, vcos1); + VertexBuffer_set_attrib(vbo, n1_id, 2 * i, n1); + VertexBuffer_set_attrib(vbo, n2_id, 2 * i, n2); + + VertexBuffer_set_attrib(vbo, pos_id, 2 * i + 1, vcos2); + VertexBuffer_set_attrib(vbo, n1_id, 2 * i + 1, n1); + VertexBuffer_set_attrib(vbo, n2_id, 2 * i + 1, n2); - VertexBuffer_set_attrib(vbo, pos_id, 2 * i + 1, vcos2); - VertexBuffer_set_attrib(vbo, n1_id, 2 * i + 1, n1); - VertexBuffer_set_attrib(vbo, n2_id, 2 * i + 1, n2); + gpu_edge_idx += 2; + } + } + if (gpu_edge_idx != vertex_ct) { + VertexBuffer_resize_data(vbo, gpu_edge_idx); } cache->fancy_edges = Batch_create(PRIM_LINES, vbo, NULL); @@ -1209,12 +1295,16 @@ static void mesh_batch_cache_create_overlay_batches(Mesh *me) int gpu_vert_idx = 0; for (int i = 0; i < tri_ct; ++i) { int tri_vert_idx[3], tri_edge_idx[3]; - mesh_render_data_looptri_vert_edge_indices_get(mrdata, i, tri_vert_idx, tri_edge_idx); - add_overlay_tri(mrdata, vbo, pos_id, data_id, - tri_vert_idx, tri_edge_idx, i, gpu_vert_idx); - gpu_vert_idx += 3; + if (mesh_render_data_looptri_vert_edge_indices_get(mrdata, i, tri_vert_idx, tri_edge_idx)) { + add_overlay_tri( + mrdata, vbo, pos_id, data_id, + tri_vert_idx, tri_edge_idx, i, gpu_vert_idx); + gpu_vert_idx += 3; + } + } + if (gpu_vert_idx != tri_ct * 3) { + VertexBuffer_resize_data(vbo, gpu_vert_idx); } - cache->overlay_triangles = Batch_create(PRIM_TRIANGLES, vbo, NULL); } @@ -1225,10 +1315,15 @@ static void mesh_batch_cache_create_overlay_batches(Mesh *me) int gpu_vert_idx = 0; for (int i = 0; i < ledge_ct; ++i) { int vert_idx[2]; - mesh_render_data_edge_verts_indices_get(mrdata, mrdata->loose_edges[i], vert_idx); - add_overlay_loose_edge(mrdata, vbo, pos_id, data_id, - vert_idx[0], vert_idx[1], mrdata->loose_edges[i], gpu_vert_idx); - gpu_vert_idx += 2; + if (mesh_render_data_edge_verts_indices_get(mrdata, mrdata->loose_edges[i], vert_idx)) { + add_overlay_loose_edge( + mrdata, vbo, pos_id, data_id, + vert_idx[0], vert_idx[1], mrdata->loose_edges[i], gpu_vert_idx); + gpu_vert_idx += 2; + } + } + if (gpu_vert_idx != ledge_ct * 2) { + VertexBuffer_resize_data(vbo, gpu_vert_idx); } cache->overlay_loose_edges = Batch_create(PRIM_LINES, vbo, NULL); } @@ -1310,19 +1405,20 @@ Batch *BKE_mesh_batch_cache_get_overlay_facedots(Mesh *me) float pcenter[3], pnor[3]; bool selected = false; - mesh_render_data_pnors_pcenter_select_get(mrdata, i, pnor, pcenter, &selected); + if (mesh_render_data_pnors_pcenter_select_get(mrdata, i, pnor, pcenter, &selected)) { #if USE_10_10_10 - PackedNormal nor = { .x = 0, .y = 0, .z = -511 }; - nor = convert_i10_v3(pnor); - nor.w = selected ? 1 : 0; - VertexBuffer_set_attrib(vbo, data_id, i, &nor); + PackedNormal nor = { .x = 0, .y = 0, .z = -511 }; + nor = convert_i10_v3(pnor); + nor.w = selected ? 1 : 0; + VertexBuffer_set_attrib(vbo, data_id, i, &nor); #else - float nor[4] = {pnor[0], pnor[1], pnor[2], selected ? 1 : 0}; - VertexBuffer_set_attrib(vbo, data_id, i, nor); + float nor[4] = {pnor[0], pnor[1], pnor[2], selected ? 1 : 0}; + VertexBuffer_set_attrib(vbo, data_id, i, nor); #endif - VertexBuffer_set_attrib(vbo, pos_id, i, pcenter); + VertexBuffer_set_attrib(vbo, pos_id, i, pcenter); + } } cache->overlay_facedots = Batch_create(PRIM_POINTS, vbo, NULL); |