Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_render.c')
-rw-r--r--source/blender/blenkernel/intern/mesh_render.c1202
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