diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_render.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_render.c | 1202 |
1 files changed, 942 insertions, 260 deletions
diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c index fd0f49810fb..dbe99acc10b 100644 --- a/source/blender/blenkernel/intern/mesh_render.c +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -31,6 +31,10 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" +#include "BLI_edgehash.h" +#include "BLI_math_vector.h" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -41,182 +45,680 @@ #include "BKE_mesh.h" #include "BKE_mesh_render.h" +#include "bmesh.h" + #include "GPU_batch.h" /* ---------------------------------------------------------------------- */ -/* Mesh Interface */ - -#define MESH_RENDER_FUNCTION(func_name) \ - if (me->edit_btmesh && me->edit_btmesh->derivedFinal) { \ - return mesh_bmesh_##func_name(me); \ - } \ - else { \ - return mesh_struct_##func_name(me); \ - } - - -/* Mesh Implementation */ +/* Mesh/BMesh Interface, direct access to basic data. */ -static int mesh_struct_get_num_edges(Mesh *me) +static int mesh_render_verts_num_get(Mesh *me) { - return me->totedge; + return me->edit_btmesh ? me->edit_btmesh->bm->totvert : me->totvert; } -static int mesh_struct_get_num_verts(Mesh *me) +static int mesh_render_edges_num_get(Mesh *me) { - return me->totvert; + return me->edit_btmesh ? me->edit_btmesh->bm->totedge : me->totedge; } -static int mesh_struct_get_num_faces(Mesh *me) +static int mesh_render_looptri_num_get(Mesh *me) { - BKE_mesh_tessface_ensure(me); - return me->totface; + return me->edit_btmesh ? me->edit_btmesh->tottri : poly_to_tri_count(me->totpoly, me->totloop); } -static int mesh_struct_get_num_polys(Mesh *me) +static int mesh_render_polys_num_get(Mesh *me) { - return me->totpoly; + return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly; } -static MEdge *mesh_struct_get_array_edge(Mesh *me) +static int UNUSED_FUNCTION(mesh_render_loops_num_get)(Mesh *me) { - return CustomData_get_layer(&me->edata, CD_MEDGE); + return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop; } -static MFace *mesh_struct_get_array_face(Mesh *me) +/* ---------------------------------------------------------------------- */ +/* Mesh/BMesh Interface, indirect, partially cached access to complex data. */ + +typedef struct EdgeAdjacentPolys { + int count; + int face_index[2]; +} EdgeAdjacentPolys; + +typedef struct MeshRenderData { + int types; + + int totvert; + int totedge; + int tottri; + int totloop; + int totpoly; + int totlvert; + int totledge; + + BMEditMesh *edit_bmesh; + MVert *mvert; + MEdge *medge; + MLoop *mloop; + MPoly *mpoly; + + BMVert *eve_act; + BMEdge *eed_act; + BMFace *efa_act; + + int crease_ofs; + int bweight_ofs; + + /* Data created on-demand (usually not for bmesh-based data). */ + EdgeHash *ehash; + EdgeAdjacentPolys *edges_adjacent_polys; + MLoopTri *mlooptri; + int *loose_edges; + int *loose_verts; + + float (*poly_normals)[3]; + short (*poly_normals_short)[3]; + short (*vert_normals_short)[3]; +} MeshRenderData; + +enum { + MR_DATATYPE_VERT = 1 << 0, + MR_DATATYPE_EDGE = 1 << 1, + MR_DATATYPE_LOOPTRI = 1 << 2, + MR_DATATYPE_LOOP = 1 << 3, + MR_DATATYPE_POLY = 1 << 4, + MR_DATATYPE_OVERLAY = 1 << 5, +}; + +static MeshRenderData *mesh_render_data_create(Mesh *me, const int types) { - BKE_mesh_tessface_ensure(me); - return CustomData_get_layer(&me->fdata, CD_MFACE); + MeshRenderData *mrdata = MEM_callocN(sizeof(*mrdata), __func__); + mrdata->types = types; + + if (me->edit_btmesh) { + BMEditMesh *embm = me->edit_btmesh; + BMesh *bm = embm->bm; + + mrdata->edit_bmesh = embm; + + int bm_ensure_types = 0; + if (types & (MR_DATATYPE_VERT)) { + mrdata->totvert = bm->totvert; + bm_ensure_types |= BM_VERT; + } + if (types & (MR_DATATYPE_EDGE)) { + mrdata->totedge = bm->totedge; + bm_ensure_types |= BM_EDGE; + } + if (types & MR_DATATYPE_LOOPTRI) { + BKE_editmesh_tessface_calc(embm); + mrdata->tottri = embm->tottri; + } + if (types & MR_DATATYPE_LOOP) { + mrdata->totloop = bm->totloop; + bm_ensure_types |= BM_LOOP; + } + if (types & MR_DATATYPE_POLY) { + mrdata->totpoly = bm->totface; + bm_ensure_types |= BM_FACE; + } + if (types & MR_DATATYPE_OVERLAY) { + mrdata->efa_act = BM_mesh_active_face_get(bm, false, true); + mrdata->eed_act = BM_mesh_active_edge_get(bm); + mrdata->eve_act = BM_mesh_active_vert_get(bm); + mrdata->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE); + mrdata->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT); + } + BM_mesh_elem_index_ensure(bm, bm_ensure_types); + BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP); + if (types & MR_DATATYPE_OVERLAY) { + mrdata->totlvert = mrdata->totledge = 0; + + int *lverts = mrdata->loose_verts = MEM_mallocN(mrdata->totvert * sizeof(int), "Loose Vert"); + int *ledges = mrdata->loose_edges = MEM_mallocN(mrdata->totedge * sizeof(int), "Loose Edges"); + + for (int i = 0; i < mrdata->totvert; ++i) { + BMVert *bv = BM_vert_at_index(bm, i); + + /* Loose vert */ + if (bv->e == NULL) { + lverts[mrdata->totlvert] = BM_elem_index_get(bv); + mrdata->totlvert++; + continue; + } + + /* Find Loose Edges */ + BMEdge *e_iter, *e_first; + e_first = e_iter = bv->e; + do { + if (e_iter->l == NULL) { + BMVert *other_vert = BM_edge_other_vert(e_iter, bv); + + /* Verify we do not add the same edge twice */ + if (BM_elem_index_get(other_vert) > i) { + ledges[mrdata->totledge] = BM_elem_index_get(e_iter); + mrdata->totledge++; + } + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, bv)) != e_first); + } + mrdata->loose_verts = MEM_reallocN(mrdata->loose_verts, mrdata->totlvert * sizeof(int)); + mrdata->loose_edges = MEM_reallocN(mrdata->loose_edges, mrdata->totledge * sizeof(int)); + } + } + else { + if (types & (MR_DATATYPE_VERT)) { + mrdata->totvert = me->totvert; + mrdata->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); + } + if (types & (MR_DATATYPE_EDGE)) { + mrdata->totedge = me->totedge; + mrdata->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + } + if (types & MR_DATATYPE_LOOPTRI) { + const int tottri = mrdata->tottri = poly_to_tri_count(me->totpoly, me->totloop); + mrdata->mlooptri = MEM_mallocN(sizeof(*mrdata->mlooptri) * tottri, __func__); + BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mrdata->mlooptri); + } + if (types & MR_DATATYPE_LOOP) { + mrdata->totloop = me->totloop; + mrdata->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + } + if (types & MR_DATATYPE_POLY) { + mrdata->totpoly = me->totpoly; + mrdata->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); + } + } + + return mrdata; } -static MLoop *mesh_struct_get_array_loop(Mesh *me) +static void mesh_render_data_free(MeshRenderData *mrdata) { - return me->mloop; + if (mrdata->ehash) { + BLI_edgehash_free(mrdata->ehash, NULL); + } + if (mrdata->loose_verts) { + MEM_freeN(mrdata->loose_verts); + } + if (mrdata->loose_edges) { + MEM_freeN(mrdata->loose_edges); + } + if (mrdata->edges_adjacent_polys) { + MEM_freeN(mrdata->edges_adjacent_polys); + } + if (mrdata->mlooptri) { + MEM_freeN(mrdata->mlooptri); + } + if (mrdata->poly_normals) { + MEM_freeN(mrdata->poly_normals); + } + if (mrdata->poly_normals_short) { + MEM_freeN(mrdata->poly_normals_short); + } + if (mrdata->vert_normals_short) { + MEM_freeN(mrdata->vert_normals_short); + } + MEM_freeN(mrdata); } -static MPoly *mesh_struct_get_array_poly(Mesh *me) +static int mesh_render_data_verts_num_get(const MeshRenderData *mrdata) { - return me->mpoly; + BLI_assert(mrdata->types & MR_DATATYPE_VERT); + return mrdata->totvert; } -static MVert *mesh_struct_get_array_vert(Mesh *me) +static int mesh_render_data_loose_verts_num_get(const MeshRenderData *mrdata) { - return CustomData_get_layer(&me->vdata, CD_MVERT); + BLI_assert(mrdata->types & MR_DATATYPE_OVERLAY); + return mrdata->totlvert; } -/* BMesh Implementation */ - -/* NOTE: we may want to get rid of Derived Mesh and - * access BMesh directly */ - -static int mesh_bmesh_get_num_verts(Mesh *me) +static int mesh_render_data_edges_num_get(const MeshRenderData *mrdata) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getNumVerts(dm); + BLI_assert(mrdata->types & MR_DATATYPE_EDGE); + return mrdata->totedge; } -static int mesh_bmesh_get_num_edges(Mesh *me) +static int mesh_render_data_loose_edges_num_get(const MeshRenderData *mrdata) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getNumEdges(dm); + BLI_assert(mrdata->types & MR_DATATYPE_OVERLAY); + return mrdata->totledge; } -static int mesh_bmesh_get_num_faces(Mesh *me) +static int mesh_render_data_looptri_num_get(const MeshRenderData *mrdata) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getNumTessFaces(dm); + BLI_assert(mrdata->types & MR_DATATYPE_LOOPTRI); + return mrdata->tottri; } -static int mesh_bmesh_get_num_polys(Mesh *me) +static int UNUSED_FUNCTION(mesh_render_data_loops_num_get)(const MeshRenderData *mrdata) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getNumPolys(dm); + BLI_assert(mrdata->types & MR_DATATYPE_LOOP); + return mrdata->totloop; } -static MEdge *mesh_bmesh_get_array_edge(Mesh *me) +static int mesh_render_data_polys_num_get(const MeshRenderData *mrdata) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getEdgeArray(dm); + BLI_assert(mrdata->types & MR_DATATYPE_POLY); + return mrdata->totpoly; } -static MFace *mesh_bmesh_get_array_face(Mesh *me) +static float *mesh_render_data_vert_co(const MeshRenderData *mrdata, const int vert_idx) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getTessFaceArray(dm); + BLI_assert(mrdata->types & MR_DATATYPE_VERT); + + if (mrdata->edit_bmesh) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, vert_idx); + return bv->co; + } + else { + return mrdata->mvert[vert_idx].co; + } } -static MLoop *mesh_bmesh_get_array_loop(Mesh *me) +static short *mesh_render_data_vert_nor(const MeshRenderData *mrdata, const int vert_idx) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getLoopArray(dm); + BLI_assert(mrdata->types & MR_DATATYPE_VERT); + + if (mrdata->edit_bmesh) { + static short fno[3]; + BMesh *bm = mrdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, vert_idx); + normal_float_to_short_v3(fno, bv->no); + return fno; + } + else { + return mrdata->mvert[vert_idx].no; + } } -static MPoly *mesh_bmesh_get_array_poly(Mesh *me) +static void mesh_render_data_edge_verts_indices_get(const MeshRenderData *mrdata, const int edge_idx, int r_vert_idx[2]) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getPolyArray(dm); + BLI_assert(mrdata->types & MR_DATATYPE_EDGE); + + if (mrdata->edit_bmesh) { + const BMEdge *bm_edge = BM_edge_at_index(mrdata->edit_bmesh->bm, edge_idx); + r_vert_idx[0] = BM_elem_index_get(bm_edge->v1); + r_vert_idx[1] = BM_elem_index_get(bm_edge->v2); + } + else { + const MEdge *me = &mrdata->medge[edge_idx]; + r_vert_idx[0] = me->v1; + r_vert_idx[1] = me->v2; + } } -static MVert *mesh_bmesh_get_array_vert(Mesh *me) +static void mesh_render_data_pnors_pcenter_select_get(MeshRenderData *mrdata, const int poly, float pnors[3], float center[3], bool *selected) { - BMEditMesh *bm = me->edit_btmesh; - DerivedMesh *dm = bm->derivedFinal; - return dm->getVertArray(dm); + BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (mrdata->edit_bmesh) { + const BMFace *bf = BM_face_at_index(mrdata->edit_bmesh->bm, poly); + BM_face_calc_center_mean(bf, center); + BM_face_calc_normal(bf, pnors); + *selected = (BM_elem_flag_test(bf, BM_ELEM_SELECT) != 0) ? true : false; + } + else { + MVert *mvert = mrdata->mvert; + const MPoly *mpoly = mrdata->mpoly + poly; + const MLoop *mloop = mrdata->mloop + mpoly->loopstart; + + BKE_mesh_calc_poly_center(mpoly, mloop, mvert, center); + BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, pnors); + + *selected = false; /* No selection if not in edit mode */ + } } -/* Mesh API */ +static bool mesh_render_data_edge_exists(MeshRenderData *mrdata, const int v1, const int v2) +{ + BLI_assert(mrdata->types & MR_DATATYPE_EDGE); + + if (mrdata->edit_bmesh) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMVert *bv1 = BM_vert_at_index(bm, v1); + BMVert *bv2 = BM_vert_at_index(bm, v2); + return BM_edge_exists(bv1, bv2) != NULL; + } + else { + EdgeHash *ehash = mrdata->ehash; + + if (!ehash) { + /* Create edge hash on demand. */ + ehash = mrdata->ehash = BLI_edgehash_new(__func__); -static int mesh_render_get_num_edges(Mesh *me) + MEdge *medge = mrdata->medge; + for (int i = 0; i < mrdata->totedge; i++, medge++) { + BLI_edgehash_insert(ehash, medge->v1, medge->v2, medge); + } + } + + return BLI_edgehash_lookup(ehash, v1, v2) != NULL; + } +} + +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) { - MESH_RENDER_FUNCTION(get_num_edges); + 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); + *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; + } + } + else { + MVert *mvert = mrdata->mvert; + MEdge *medge = mrdata->medge; + EdgeAdjacentPolys *eap = mrdata->edges_adjacent_polys; + float (*pnors)[3] = mrdata->poly_normals; + + if (!eap) { + const MLoop *mloop = mrdata->mloop; + const MPoly *mpoly = mrdata->mpoly; + const int poly_ct = mrdata->totpoly; + const bool do_pnors = (pnors == NULL); + + eap = mrdata->edges_adjacent_polys = MEM_callocN(sizeof(*eap) * mrdata->totedge, __func__); + if (do_pnors) { + pnors = mrdata->poly_normals = MEM_mallocN(sizeof(*pnors) * poly_ct, __func__); + } + + for (int i = 0; i < poly_ct; i++, mpoly++) { + if (do_pnors) { + BKE_mesh_calc_poly_normal(mpoly, mloop + mpoly->loopstart, mvert, pnors[i]); + } + + const int loopend = mpoly->loopstart + mpoly->totloop; + for (int j = mpoly->loopstart; j < loopend; j++) { + const int edge_idx = mloop[j].e; + if (eap[edge_idx].count < 2) { + eap[edge_idx].face_index[eap[edge_idx].count] = i; + } + eap[edge_idx].count++; + } + } + } + BLI_assert(eap && pnors); + + *r_vco1 = mvert[medge[edge_index].v1].co; + *r_vco2 = mvert[medge[edge_index].v2].co; + 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; + } + } + + return false; } -static int mesh_render_get_num_faces(Mesh *me) +static void mesh_render_data_looptri_verts_indices_get(const MeshRenderData *mrdata, const int tri_idx, int r_vert_idx[3]) { - MESH_RENDER_FUNCTION(get_num_faces); + BLI_assert(mrdata->types & (MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP)); + + if (mrdata->edit_bmesh) { + const BMLoop **bm_looptri = (const BMLoop **)mrdata->edit_bmesh->looptris[tri_idx]; + 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); + } + else { + const MLoopTri *mlt = &mrdata->mlooptri[tri_idx]; + r_vert_idx[0] = mrdata->mloop[mlt->tri[0]].v; + r_vert_idx[1] = mrdata->mloop[mlt->tri[1]].v; + r_vert_idx[2] = mrdata->mloop[mlt->tri[2]].v; + } } -static int mesh_render_get_num_polys(Mesh *me) +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]) { - MESH_RENDER_FUNCTION(get_num_polys); + 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]; + short (*pnors_short)[3] = mrdata->poly_normals_short; + short (*vnors_short)[3] = mrdata->vert_normals_short; + + if (!pnors_short) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMIter fiter; + BMFace *face; + int i; + + pnors_short = mrdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * mrdata->totpoly, __func__); + BM_ITER_MESH_INDEX(face, &fiter, bm, BM_FACES_OF_MESH, i) { + normal_float_to_short_v3(pnors_short[i], face->no); + } + } + if (!vnors_short) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMIter viter; + BMVert *vert; + int i; + + vnors_short = mrdata->vert_normals_short = MEM_mallocN(sizeof(*vnors_short) * mrdata->totvert, __func__); + BM_ITER_MESH_INDEX(vert, &viter, bm, BM_VERT, i) { + normal_float_to_short_v3(vnors_short[i], vert->no); + } + } + + (*r_vert_cos)[0] = bm_looptri[0]->v->co; + (*r_vert_cos)[1] = bm_looptri[1]->v->co; + (*r_vert_cos)[2] = bm_looptri[2]->v->co; + *r_tri_nor = pnors_short[BM_elem_index_get(bm_looptri[0]->f)]; + (*r_vert_nors)[0] = vnors_short[BM_elem_index_get(bm_looptri[0]->v)]; + (*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); + } + else { + const MLoopTri *mlt = &mrdata->mlooptri[tri_idx]; + short (*pnors_short)[3] = mrdata->poly_normals_short; + + if (!pnors_short) { + float (*pnors)[3] = mrdata->poly_normals; + + if (!pnors) { + pnors = mrdata->poly_normals = MEM_mallocN(sizeof(*pnors) * mrdata->totpoly, __func__); + BKE_mesh_calc_normals_poly( + mrdata->mvert, NULL, mrdata->totvert, + mrdata->mloop, mrdata->mpoly, mrdata->totloop, mrdata->totpoly, pnors, true); + } + + pnors_short = mrdata->poly_normals_short = MEM_mallocN(sizeof(*pnors_short) * mrdata->totpoly, __func__); + for (int i = 0; i < mrdata->totpoly; i++) { + normal_float_to_short_v3(pnors_short[i], pnors[i]); + } + } + + (*r_vert_cos)[0] = mrdata->mvert[mrdata->mloop[mlt->tri[0]].v].co; + (*r_vert_cos)[1] = mrdata->mvert[mrdata->mloop[mlt->tri[1]].v].co; + (*r_vert_cos)[2] = mrdata->mvert[mrdata->mloop[mlt->tri[2]].v].co; + *r_tri_nor = pnors_short[mlt->poly]; + (*r_vert_nors)[0] = mrdata->mvert[mrdata->mloop[mlt->tri[0]].v].no; + (*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; + } } -static int mesh_render_get_num_verts(Mesh *me) +/* First 2 bytes are bit flags + * 3rd is for sharp edges + * 4rd is for creased edges */ +enum { + VFLAG_VERTEX_ACTIVE = 1 << 0, + VFLAG_VERTEX_SELECTED = 1 << 1, + VFLAG_FACE_ACTIVE = 1 << 2, + VFLAG_FACE_SELECTED = 1 << 3, +}; + +enum { + VFLAG_EDGE_EXISTS = 1 << 0, + VFLAG_EDGE_ACTIVE = 1 << 1, + VFLAG_EDGE_SELECTED = 1 << 2, + VFLAG_EDGE_SEAM = 1 << 3, + VFLAG_EDGE_SHARP = 1 << 4, + /* Beware to not go over 1 << 7 + * (see gpu_shader_edit_overlay_geom.glsl) */ +}; + +static unsigned char mesh_render_data_looptri_flag(MeshRenderData *mrdata, const int f) { - MESH_RENDER_FUNCTION(get_num_verts); + unsigned char fflag = 0; + + if (mrdata->edit_bmesh) { + BMFace *bf = mrdata->edit_bmesh->looptris[f][0]->f; + + if (bf == mrdata->efa_act) + fflag |= VFLAG_FACE_ACTIVE; + + if (BM_elem_flag_test(bf, BM_ELEM_SELECT)) + fflag |= VFLAG_FACE_SELECTED; + } + + return fflag; } -static MEdge *mesh_render_get_array_edge(Mesh *me) +static unsigned char *mesh_render_data_edge_flag( + MeshRenderData *mrdata, const int v1, const int v2, const int e) { - MESH_RENDER_FUNCTION(get_array_edge); + static unsigned char eflag[4]; + memset(eflag, 0, sizeof(char) * 4); + + /* if edge exists */ + if (mrdata->edit_bmesh) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMEdge *be = NULL; + + if (e != -1) be = BM_edge_at_index(bm, e); + else be = BM_edge_exists(BM_vert_at_index(bm, v1), + BM_vert_at_index(bm, v2)); + + if (be != NULL) { + + eflag[1] |= VFLAG_EDGE_EXISTS; + + if (be == mrdata->eed_act) + eflag[1] |= VFLAG_EDGE_ACTIVE; + + if (BM_elem_flag_test(be, BM_ELEM_SELECT)) + eflag[1] |= VFLAG_EDGE_SELECTED; + + if (BM_elem_flag_test(be, BM_ELEM_SEAM)) + eflag[1] |= VFLAG_EDGE_SEAM; + + if (!BM_elem_flag_test(be, BM_ELEM_SMOOTH)) + eflag[1] |= VFLAG_EDGE_SHARP; + + /* Use a byte for value range */ + if (mrdata->crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(be, mrdata->crease_ofs); + if (crease > 0) { + eflag[2] = (char)(crease * 255.0f); + } + } + + /* Use a byte for value range */ + if (mrdata->bweight_ofs != -1) { + float bweight = BM_ELEM_CD_GET_FLOAT(be, mrdata->bweight_ofs); + if (bweight > 0) { + eflag[3] = (char)(bweight * 255.0f); + } + } + } + } + else if ((e == -1) && mesh_render_data_edge_exists(mrdata, v1, v2)) { + eflag[1] |= VFLAG_EDGE_EXISTS; + } + + return eflag; } -static MFace *mesh_render_get_array_face(Mesh *me) +static unsigned char mesh_render_data_vertex_flag(MeshRenderData *mrdata, const int v) { - MESH_RENDER_FUNCTION(get_array_face); + + unsigned char vflag = 0; + + if (mrdata->edit_bmesh) { + BMesh *bm = mrdata->edit_bmesh->bm; + BMVert *bv = BM_vert_at_index(bm, v); + + /* Current vertex */ + if (bv == mrdata->eve_act) + vflag |= VFLAG_VERTEX_ACTIVE; + + if (BM_elem_flag_test(bv, BM_ELEM_SELECT)) + vflag |= VFLAG_VERTEX_SELECTED; + } + + return vflag; } -static MLoop *mesh_render_get_array_loop(Mesh *me) +static void add_overlay_tri( + MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int v1, const int v2, const int v3, const int f, const int base_vert_idx) { - MESH_RENDER_FUNCTION(get_array_loop); + const float *pos = mesh_render_data_vert_co(mrdata, v1); + unsigned char *eflag = mesh_render_data_edge_flag(mrdata, v2, v3, -1); + unsigned char fflag = mesh_render_data_looptri_flag(mrdata, f); + unsigned char vflag = mesh_render_data_vertex_flag(mrdata, v1); + eflag[0] = fflag | vflag; + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, eflag); + + pos = mesh_render_data_vert_co(mrdata, v2); + eflag = mesh_render_data_edge_flag(mrdata, v1, v3, -1); + vflag = mesh_render_data_vertex_flag(mrdata, v2); + eflag[0] = fflag | vflag; + setAttrib(vbo, pos_id, base_vert_idx + 1, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 1, eflag); + + pos = mesh_render_data_vert_co(mrdata, v3); + eflag = mesh_render_data_edge_flag(mrdata, v1, v2, -1); + vflag = mesh_render_data_vertex_flag(mrdata, v3); + eflag[0] = fflag | vflag; + setAttrib(vbo, pos_id, base_vert_idx + 2, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 2, eflag); } -static MPoly *mesh_render_get_array_poly(Mesh *me) +static void add_overlay_loose_edge( + MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int v1, const int v2, const int e, const int base_vert_idx) { - MESH_RENDER_FUNCTION(get_array_poly); + unsigned char *eflag = mesh_render_data_edge_flag(mrdata, 0, 0, e); + const float *pos = mesh_render_data_vert_co(mrdata, v1); + eflag[0] = mesh_render_data_vertex_flag(mrdata, v1); + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, eflag); + + pos = mesh_render_data_vert_co(mrdata, v2); + eflag[0] = mesh_render_data_vertex_flag(mrdata, v2); + setAttrib(vbo, pos_id, base_vert_idx + 1, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 1, eflag); } -static MVert *mesh_render_get_array_vert(Mesh *me) +static void add_overlay_loose_vert( + MeshRenderData *mrdata, VertexBuffer *vbo, const unsigned int pos_id, const unsigned int edgeMod_id, + const int v, const int base_vert_idx) { - MESH_RENDER_FUNCTION(get_array_vert); + unsigned char vflag[4] = {0, 0, 0, 0}; + const float *pos = mesh_render_data_vert_co(mrdata, v); + vflag[0] = mesh_render_data_vertex_flag(mrdata, v); + setAttrib(vbo, pos_id, base_vert_idx + 0, pos); + setAttrib(vbo, edgeMod_id, base_vert_idx + 0, vflag); } /* ---------------------------------------------------------------------- */ @@ -224,6 +726,7 @@ static MVert *mesh_render_get_array_vert(Mesh *me) typedef struct MeshBatchCache { VertexBuffer *pos_in_order; + VertexBuffer *nor_in_order; ElementList *edges_in_order; ElementList *triangles_in_order; @@ -231,18 +734,31 @@ typedef struct MeshBatchCache { Batch *all_edges; Batch *all_triangles; + VertexBuffer *pos_with_normals; + Batch *triangles_with_normals; + Batch *points_with_normals; Batch *fancy_edges; /* owns its vertex buffer (not shared) */ - Batch *overlay_edges; /* owns its vertex buffer */ + + /* TODO : split in 2 buffers to avoid unnecessary + * data transfer when selecting/deselecting + * and combine into one batch and use offsets to render + * Tri / edges / verts separately */ + Batch *overlay_triangles; + Batch *overlay_loose_verts; + Batch *overlay_loose_edges; + Batch *overlay_facedots; /* settings to determine if cache is invalid */ bool is_dirty; int tot_edges; - int tot_faces; + int tot_tris; int tot_polys; int tot_verts; bool is_editmode; } MeshBatchCache; +/* Batch cache management. */ + static bool mesh_batch_cache_valid(Mesh *me) { MeshBatchCache *cache = me->batch_cache; @@ -262,10 +778,10 @@ static bool mesh_batch_cache_valid(Mesh *me) if (cache->is_editmode) { return false; } - else if ((cache->tot_edges != mesh_render_get_num_edges(me)) || - (cache->tot_faces != mesh_render_get_num_faces(me)) || - (cache->tot_polys != mesh_render_get_num_polys(me)) || - (cache->tot_verts != mesh_render_get_num_verts(me))) + else if ((cache->tot_verts != mesh_render_verts_num_get(me)) || + (cache->tot_edges != mesh_render_edges_num_get(me)) || + (cache->tot_tris != mesh_render_looptri_num_get(me)) || + (cache->tot_polys != mesh_render_polys_num_get(me))) { return false; } @@ -277,13 +793,21 @@ static bool mesh_batch_cache_valid(Mesh *me) static void mesh_batch_cache_init(Mesh *me) { MeshBatchCache *cache = me->batch_cache; + + if (!cache) { + cache = me->batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + cache->is_editmode = me->edit_btmesh != NULL; if (cache->is_editmode == false) { - cache->tot_edges = mesh_render_get_num_edges(me); - cache->tot_faces = mesh_render_get_num_faces(me); - cache->tot_polys = mesh_render_get_num_polys(me); - cache->tot_verts = mesh_render_get_num_verts(me); + cache->tot_edges = mesh_render_edges_num_get(me); + cache->tot_tris = mesh_render_looptri_num_get(me); + cache->tot_polys = mesh_render_polys_num_get(me); + cache->tot_verts = mesh_render_verts_num_get(me); } cache->is_dirty = false; @@ -292,57 +816,167 @@ static void mesh_batch_cache_init(Mesh *me) static MeshBatchCache *mesh_batch_cache_get(Mesh *me) { if (!mesh_batch_cache_valid(me)) { - BKE_mesh_batch_cache_free(me); - me->batch_cache = MEM_callocN(sizeof(MeshBatchCache), "MeshBatchCache"); + BKE_mesh_batch_cache_clear(me); mesh_batch_cache_init(me); } return me->batch_cache; } -static VertexBuffer *mesh_batch_cache_get_pos_in_order(Mesh *me) +void BKE_mesh_batch_cache_dirty(struct Mesh *me) { - MeshBatchCache *cache = mesh_batch_cache_get(me); + MeshBatchCache *cache = me->batch_cache; + if (cache) { + cache->is_dirty = true; + } +} + +void BKE_mesh_batch_selection_dirty(struct Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (cache) { + /* TODO Separate Flag vbo */ + if (cache->overlay_triangles) { + Batch_discard_all(cache->overlay_triangles); + cache->overlay_triangles = NULL; + } + if (cache->overlay_loose_verts) { + Batch_discard_all(cache->overlay_loose_verts); + cache->overlay_loose_verts = NULL; + } + if (cache->overlay_loose_edges) { + Batch_discard_all(cache->overlay_loose_edges); + cache->overlay_loose_edges = NULL; + } + if (cache->overlay_facedots) { + Batch_discard_all(cache->overlay_facedots); + cache->overlay_facedots = NULL; + } + } +} + +void BKE_mesh_batch_cache_clear(Mesh *me) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + if (cache->all_verts) Batch_discard(cache->all_verts); + if (cache->all_edges) Batch_discard(cache->all_edges); + if (cache->all_triangles) Batch_discard(cache->all_triangles); + + if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); + if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); + if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); + + if (cache->overlay_triangles) Batch_discard_all(cache->overlay_triangles); + if (cache->overlay_loose_verts) Batch_discard_all(cache->overlay_loose_verts); + if (cache->overlay_loose_edges) Batch_discard_all(cache->overlay_loose_edges); + if (cache->overlay_facedots) Batch_discard_all(cache->overlay_facedots); + + if (cache->triangles_with_normals) Batch_discard(cache->triangles_with_normals); + if (cache->points_with_normals) Batch_discard(cache->points_with_normals); + if (cache->pos_with_normals) VertexBuffer_discard(cache->pos_with_normals); + + + if (cache->fancy_edges) { + Batch_discard_all(cache->fancy_edges); + } +} + +void BKE_mesh_batch_cache_free(Mesh *me) +{ + BKE_mesh_batch_cache_clear(me); + MEM_SAFE_FREE(me->batch_cache); +} + +/* Batch cache usage. */ + +static VertexBuffer *mesh_batch_cache_get_pos_and_normals(MeshRenderData *mrdata, MeshBatchCache *cache) +{ + BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY)); + + if (cache->pos_with_normals == NULL) { + unsigned int vidx = 0, nidx = 0; + + static VertexFormat format = { 0 }; + static unsigned int pos_id, nor_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT); + } + + const int tottri = mesh_render_data_looptri_num_get(mrdata); + + cache->pos_with_normals = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(cache->pos_with_normals, tottri * 3); + + for (int i = 0; i < tottri; i++) { + float *tri_vert_cos[3]; + short *tri_nor, *tri_vert_nors[3]; + + const bool is_smooth = mesh_render_data_looptri_cos_nors_smooth_get(mrdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors); + + if (is_smooth) { + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[0]); + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[1]); + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_vert_nors[2]); + } + else { + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + setAttrib(cache->pos_with_normals, nor_id, nidx++, tri_nor); + } + + setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[0]); + setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[1]); + setAttrib(cache->pos_with_normals, pos_id, vidx++, tri_vert_cos[2]); + } + } + return cache->pos_with_normals; +} +static VertexBuffer *mesh_batch_cache_get_pos_and_nor_in_order(MeshRenderData *mrdata, MeshBatchCache *cache) +{ + BLI_assert(mrdata->types & MR_DATATYPE_VERT); if (cache->pos_in_order == NULL) { static VertexFormat format = { 0 }; - static unsigned pos_id; + static unsigned pos_id, nor_id; if (format.attrib_ct == 0) { /* initialize vertex format */ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + nor_id = add_attrib(&format, "nor", GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT); } - const int vertex_ct = mesh_render_get_num_verts(me); - const MVert *verts = mesh_render_get_array_vert(me); + const int vertex_ct = mesh_render_data_verts_num_get(mrdata); cache->pos_in_order = VertexBuffer_create_with_format(&format); VertexBuffer_allocate_data(cache->pos_in_order, vertex_ct); -#if 0 - const unsigned stride = (verts + 1) - verts; /* or sizeof(MVert) */ - fillAttribStride(cache->pos_in_order, pos_id, stride, &verts[0].co); -#else for (int i = 0; i < vertex_ct; ++i) { - setAttrib(cache->pos_in_order, pos_id, i, &verts[i].co); + setAttrib(cache->pos_in_order, pos_id, i, mesh_render_data_vert_co(mrdata, i)); + setAttrib(cache->pos_in_order, nor_id, i, mesh_render_data_vert_nor(mrdata, i)); } -#endif } return cache->pos_in_order; } -static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me) +static ElementList *mesh_batch_cache_get_edges_in_order(MeshRenderData *mrdata, MeshBatchCache *cache) { - MeshBatchCache *cache = mesh_batch_cache_get(me); + BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE)); if (cache->edges_in_order == NULL) { - const int vertex_ct = mesh_render_get_num_verts(me); - const int edge_ct = mesh_render_get_num_edges(me); - const MEdge *edges = mesh_render_get_array_edge(me); + printf("Caching edges in order...\n"); + const int vertex_ct = mesh_render_data_verts_num_get(mrdata); + const int edge_ct = mesh_render_data_edges_num_get(mrdata); ElementListBuilder elb; ElementListBuilder_init(&elb, GL_LINES, edge_ct, vertex_ct); for (int i = 0; i < edge_ct; ++i) { - const MEdge *edge = edges + i; - add_line_vertices(&elb, edge->v1, edge->v2); + 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]); } cache->edges_in_order = ElementList_build(&elb); } @@ -350,91 +984,90 @@ static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me) return cache->edges_in_order; } -static ElementList *mesh_batch_cache_get_triangles_in_order(Mesh *me) +static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *mrdata, MeshBatchCache *cache) { - MeshBatchCache *cache = mesh_batch_cache_get(me); + BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI)); if (cache->triangles_in_order == NULL) { - const int vertex_ct = mesh_render_get_num_verts(me); - const int tessface_ct = mesh_render_get_num_faces(me); - MFace *tessfaces = mesh_render_get_array_face(me); + const int vertex_ct = mesh_render_data_verts_num_get(mrdata); + const int tri_ct = mesh_render_data_looptri_num_get(mrdata); ElementListBuilder elb; - ElementListBuilder_init(&elb, GL_TRIANGLES, tessface_ct * 2, vertex_ct); /* up to 2 triangles per tessface */ - for (int i = 0; i < tessface_ct; ++i) { - const MFace *tess = tessfaces + i; - add_triangle_vertices(&elb, tess->v1, tess->v2, tess->v3); + ElementListBuilder_init(&elb, GL_TRIANGLES, tri_ct, vertex_ct); + for (int i = 0; i < tri_ct; ++i) { + int tri_vert_idx[3]; + mesh_render_data_looptri_verts_indices_get(mrdata, i, tri_vert_idx); - if (tess->v4) { - add_triangle_vertices(&elb, tess->v1, tess->v3, tess->v4); - } + add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]); } cache->triangles_in_order = ElementList_build(&elb); } - /* NOTE: we are reallocating, it would be interesting to reallocating the memory once we - * know the exactly triangle count (like in BKE_mesh_batch_cache_get_overlay_edges) */ - return cache->triangles_in_order; } -void BKE_mesh_batch_cache_dirty(struct Mesh *me) +Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me) { - MeshBatchCache *cache = me->batch_cache; - if (cache) { - cache->is_dirty = true; + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->all_edges == NULL) { + /* create batch from Mesh */ + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE); + + cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache), + mesh_batch_cache_get_edges_in_order(mrdata, cache)); + + mesh_render_data_free(mrdata); } + + return cache->all_edges; } -void BKE_mesh_batch_cache_free(Mesh *me) +Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me) { - MeshBatchCache *cache = me->batch_cache; - if (!cache) { - return; - } - - if (cache->all_verts) Batch_discard(cache->all_verts); - if (cache->all_edges) Batch_discard(cache->all_edges); - if (cache->all_triangles) Batch_discard(cache->all_triangles); + MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache->pos_in_order) VertexBuffer_discard(cache->pos_in_order); - if (cache->edges_in_order) ElementList_discard(cache->edges_in_order); - if (cache->triangles_in_order) ElementList_discard(cache->triangles_in_order); + if (cache->all_triangles == NULL) { + /* create batch from DM */ + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI); - if (cache->fancy_edges) { - Batch_discard_all(cache->fancy_edges); - } + cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache), + mesh_batch_cache_get_triangles_in_order(mrdata, cache)); - if (cache->overlay_edges) { - Batch_discard_all(cache->overlay_edges); + mesh_render_data_free(mrdata); } - MEM_freeN(cache); - me->batch_cache = NULL; + return cache->all_triangles; } -Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me) +Batch *BKE_mesh_batch_cache_get_triangles_with_normals(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache->all_edges == NULL) { - /* create batch from Mesh */ - cache->all_edges = Batch_create(GL_LINES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_edges_in_order(me)); + if (cache->triangles_with_normals == NULL) { + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + cache->triangles_with_normals = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_and_normals(mrdata, cache), NULL); + + mesh_render_data_free(mrdata); } - return cache->all_edges; + return cache->triangles_with_normals; } -Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *me) +Batch *BKE_mesh_batch_cache_get_points_with_normals(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache->all_triangles == NULL) { - /* create batch from DM */ - cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_in_order(me), mesh_batch_cache_get_triangles_in_order(me)); + if (cache->points_with_normals == NULL) { + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + cache->points_with_normals = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_and_normals(mrdata, cache), NULL); + + mesh_render_data_free(mrdata); } - return cache->all_triangles; + return cache->points_with_normals; } Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me) @@ -443,8 +1076,11 @@ Batch *BKE_mesh_batch_cache_get_all_verts(Mesh *me) if (cache->all_verts == NULL) { /* create batch from DM */ - cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_in_order(me), NULL); - Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT); + + cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_and_nor_in_order(mrdata, cache), NULL); + + mesh_render_data_free(mrdata); } return cache->all_verts; @@ -457,7 +1093,7 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) if (cache->fancy_edges == NULL) { /* create batch from DM */ static VertexFormat format = { 0 }; - static unsigned pos_id, n1_id, n2_id; + static unsigned int pos_id, n1_id, n2_id; if (format.attrib_ct == 0) { /* initialize vertex format */ pos_id = add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT); @@ -472,48 +1108,24 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) } VertexBuffer *vbo = VertexBuffer_create_with_format(&format); - const MVert *verts = mesh_render_get_array_vert(me); - const MEdge *edges = mesh_render_get_array_edge(me); - const MPoly *polys = mesh_render_get_array_poly(me); - const MLoop *loops = mesh_render_get_array_loop(me); - const int edge_ct = mesh_render_get_num_edges(me); - const int poly_ct = mesh_render_get_num_polys(me); - - /* need normal of each face, and which faces are adjacent to each edge */ - typedef struct { - int count; - int face_index[2]; - } AdjacentFaces; - - float (*face_normal)[3] = MEM_mallocN(poly_ct * 3 * sizeof(float), "face_normal"); - AdjacentFaces *adj_faces = MEM_callocN(edge_ct * sizeof(AdjacentFaces), "adj_faces"); + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); - for (int i = 0; i < poly_ct; ++i) { - const MPoly *poly = polys + i; - - BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, verts, face_normal[i]); - - for (int j = poly->loopstart; j < (poly->loopstart + poly->totloop); ++j) { - AdjacentFaces *adj = adj_faces + loops[j].e; - if (adj->count < 2) - adj->face_index[adj->count] = i; - adj->count++; - } - } + const int edge_ct = mesh_render_data_edges_num_get(mrdata); const int vertex_ct = edge_ct * 2; /* these are GL_LINE verts, not mesh verts */ VertexBuffer_allocate_data(vbo, vertex_ct); for (int i = 0; i < edge_ct; ++i) { - const MEdge *edge = edges + i; - const AdjacentFaces *adj = adj_faces + 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); #if USE_10_10_10 PackedNormal n1value = { .x = 0, .y = 0, .z = +511 }; PackedNormal n2value = { .x = 0, .y = 0, .z = -511 }; - if (adj->count == 2) { - n1value = convert_i10_v3(face_normal[adj->face_index[0]]); - n2value = convert_i10_v3(face_normal[adj->face_index[1]]); + if (is_manifold) { + n1value = convert_i10_v3(pnor1); + n2value = convert_i10_v3(pnor2); } const PackedNormal *n1 = &n1value; @@ -522,106 +1134,176 @@ Batch *BKE_mesh_batch_cache_get_fancy_edges(Mesh *me) const float dummy1[3] = { 0.0f, 0.0f, +1.0f }; const float dummy2[3] = { 0.0f, 0.0f, -1.0f }; - const float *n1 = (adj->count == 2) ? face_normal[adj->face_index[0]] : dummy1; - const float *n2 = (adj->count == 2) ? face_normal[adj->face_index[1]] : dummy2; + const float *n1 = (is_manifold) ? pnor1 : dummy1; + const float *n2 = (is_manifold) ? pnor2 : dummy2; #endif - setAttrib(vbo, pos_id, 2 * i, &verts[edge->v1].co); + setAttrib(vbo, pos_id, 2 * i, vcos1); setAttrib(vbo, n1_id, 2 * i, n1); setAttrib(vbo, n2_id, 2 * i, n2); - setAttrib(vbo, pos_id, 2 * i + 1, &verts[edge->v2].co); + setAttrib(vbo, pos_id, 2 * i + 1, vcos2); setAttrib(vbo, n1_id, 2 * i + 1, n1); setAttrib(vbo, n2_id, 2 * i + 1, n2); } - MEM_freeN(adj_faces); - MEM_freeN(face_normal); - cache->fancy_edges = Batch_create(GL_LINES, vbo, NULL); + + mesh_render_data_free(mrdata); } return cache->fancy_edges; } -static bool edge_is_real(const MEdge *edges, int edge_ct, int v1, int v2) +static void mesh_batch_cache_create_overlay_batches(Mesh *me) { - /* TODO: same thing, except not ridiculously slow */ + /* Since MR_DATATYPE_OVERLAY is slow to generate, generate them all at once */ + int options = MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOPTRI | MR_DATATYPE_OVERLAY; - for (int e = 0; e < edge_ct; ++e) { - const MEdge *edge = edges + e; - if ((edge->v1 == v1 && edge->v2 == v2) || (edge->v1 == v2 && edge->v2 == v1)) { - return true; + MeshBatchCache *cache = mesh_batch_cache_get(me); + MeshRenderData *mrdata = mesh_render_data_create(me, options); + + static VertexFormat format = { 0 }; + static unsigned pos_id, data_id; + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); + data_id = add_attrib(&format, "data", GL_UNSIGNED_BYTE, 4, KEEP_INT); + } + + const int tri_ct = mesh_render_data_looptri_num_get(mrdata); + const int ledge_ct = mesh_render_data_loose_edges_num_get(mrdata); + const int lvert_ct = mesh_render_data_loose_verts_num_get(mrdata); + + if (cache->overlay_triangles == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, tri_ct * 3); + + int gpu_vert_idx = 0; + for (int i = 0; i < tri_ct; ++i) { + int tri_vert_idx[3]; + mesh_render_data_looptri_verts_indices_get(mrdata, i, tri_vert_idx); + add_overlay_tri(mrdata, vbo, pos_id, data_id, + tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2], i, gpu_vert_idx); + gpu_vert_idx += 3; } + + cache->overlay_triangles = Batch_create(GL_TRIANGLES, vbo, NULL); } - return false; + if (cache->overlay_loose_edges == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, ledge_ct * 2); + + 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; + } + cache->overlay_loose_edges = Batch_create(GL_LINES, vbo, NULL); + } + + if (cache->overlay_loose_verts == NULL) { + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, lvert_ct); + + int gpu_vert_idx = 0; + for (int i = 0; i < lvert_ct; ++i) { + add_overlay_loose_vert(mrdata, vbo, pos_id, data_id, + mrdata->loose_verts[i], gpu_vert_idx); + gpu_vert_idx += 1; + } + cache->overlay_loose_verts = Batch_create(GL_POINTS, vbo, NULL); + } + + mesh_render_data_free(mrdata); } -static void add_overlay_tri( - VertexBuffer *vbo, unsigned pos_id, unsigned edgeMod_id, const MVert *verts, - const MEdge *edges, int edge_ct, int v1, int v2, int v3, int base_vert_idx) +Batch *BKE_mesh_batch_cache_get_overlay_triangles(Mesh *me) { - const float edgeMods[2] = { 0.0f, 1.0f }; + MeshBatchCache *cache = mesh_batch_cache_get(me); - const float *pos = verts[v1].co; - setAttrib(vbo, pos_id, base_vert_idx + 0, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (edge_is_real(edges, edge_ct, v2, v3) ? 1 : 0)); + if (cache->overlay_triangles == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } - pos = verts[v2].co; - setAttrib(vbo, pos_id, base_vert_idx + 1, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (edge_is_real(edges, edge_ct, v3, v1) ? 1 : 0)); + return cache->overlay_triangles; +} - pos = verts[v3].co; - setAttrib(vbo, pos_id, base_vert_idx + 2, pos); - setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (edge_is_real(edges, edge_ct, v1, v2) ? 1 : 0)); +Batch *BKE_mesh_batch_cache_get_overlay_loose_edges(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_loose_edges == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } + + return cache->overlay_loose_edges; } -Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me) +Batch *BKE_mesh_batch_cache_get_overlay_loose_verts(Mesh *me) { MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache->overlay_edges == NULL) { - /* create batch from DM */ - static VertexFormat format = { 0 }; - static unsigned pos_id, edgeMod_id; + if (cache->overlay_loose_verts == NULL) { + mesh_batch_cache_create_overlay_batches(me); + } + return cache->overlay_loose_verts; +} + +Batch *BKE_mesh_batch_cache_get_overlay_facedots(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + if (cache->overlay_facedots == NULL) { + MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOP | MR_DATATYPE_POLY); + + static VertexFormat format = { 0 }; + static unsigned pos_id, data_id; if (format.attrib_ct == 0) { /* initialize vertex format */ pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT); - edgeMod_id = add_attrib(&format, "edgeWidthModulator", GL_FLOAT, 1, KEEP_FLOAT); +#if USE_10_10_10 + data_id = add_attrib(&format, "norAndFlag", COMP_I10, 4, NORMALIZE_INT_TO_FLOAT); +#else + data_id = add_attrib(&format, "norAndFlag", GL_FLOAT, 4, KEEP_FLOAT); +#endif } + + const int poly_ct = mesh_render_data_polys_num_get(mrdata); + VertexBuffer *vbo = VertexBuffer_create_with_format(&format); + VertexBuffer_allocate_data(vbo, poly_ct); - const int edge_ct = mesh_render_get_num_edges(me); - const int tessface_ct = mesh_render_get_num_faces(me); - const MVert *verts = mesh_render_get_array_vert(me); - const MEdge *edges = mesh_render_get_array_edge(me); - const MFace *tessfaces = mesh_render_get_array_face(me); + for (int i = 0; i < poly_ct; ++i) { + float pcenter[3], pnor[3]; + int selected = 0; - VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */ + mesh_render_data_pnors_pcenter_select_get(mrdata, i, pnor, pcenter, (bool *)&selected); - int gpu_vert_idx = 0; - for (int i = 0; i < tessface_ct; ++i) { - const MFace *tess = tessfaces + i; - add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v1, tess->v2, tess->v3, gpu_vert_idx); - gpu_vert_idx += 3; - /* tessface can be triangle or quad */ - if (tess->v4) { - add_overlay_tri(vbo, pos_id, edgeMod_id, verts, edges, edge_ct, tess->v3, tess->v2, tess->v4, gpu_vert_idx); - gpu_vert_idx += 3; - } - } +#if USE_10_10_10 + PackedNormal nor = { .x = 0, .y = 0, .z = -511 }; + nor = convert_i10_v3(pnor); + nor.w = selected; + setAttrib(vbo, data_id, i, &nor); +#else + float nor[4] = {pnor[0], pnor[1], pnor[2], (float)selected}; + setAttrib(vbo, data_id, i, nor); +#endif - /* in some cases all the faces are quad, so no need to reallocate */ - if (vbo->vertex_ct != gpu_vert_idx) { - VertexBuffer_resize_data(vbo, gpu_vert_idx); + setAttrib(vbo, pos_id, i, pcenter); } - cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL); + cache->overlay_facedots = Batch_create(GL_POINTS, vbo, NULL); + + mesh_render_data_free(mrdata); } - return cache->overlay_edges; + return cache->overlay_facedots; } #undef MESH_RENDER_FUNCTION |