Rework of BKE's mesh_render to support BMesh directly.

Note that since there is no (efficient) ways to get arrays of
MVert/MEdge/etc. out of a BMesh, I refactored quite heavily internals of
BKE_mesh_render.

Now, when you do need acess to mesh data to generate cached batches, you
create an abstract struct from mesh (either Mesh or BMesh if available),
and then use advanced helpers to extract needed data, on a per-item
basis (no more handling of arrays of verts/edges/... in batches code).

This allows to:
* Avoid having to create arrays of BMesh elements.
* Take advantage of existing advanced BMesh topology and connectivity data.

Reviewers: dfelinto, fclem, merwin

Differential Revision: https://developer.blender.org/D2521
This commit is contained in:
Bastien Montagne
2017-02-23 11:54:40 +01:00
parent d751676cf3
commit ef60979029
2 changed files with 524 additions and 361 deletions

View File

@@ -33,6 +33,7 @@ struct Batch;
struct Mesh;
void BKE_mesh_batch_cache_dirty(struct Mesh *me);
void BKE_mesh_batch_cache_clear(struct Mesh *me);
void BKE_mesh_batch_cache_free(struct Mesh *me);
struct Batch *BKE_mesh_batch_cache_get_all_edges(struct Mesh *me);
struct Batch *BKE_mesh_batch_cache_get_all_triangles(struct Mesh *me);

View File

@@ -31,6 +31,8 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_edgehash.h"
#include "BLI_math_vector.h"
#include "DNA_mesh_types.h"
@@ -43,200 +45,407 @@
#include "BKE_mesh.h"
#include "BKE_mesh_render.h"
#include "bmesh.h"
#include "GPU_batch.h"
/* ---------------------------------------------------------------------- */
/* Mesh Interface */
/* Mesh/BMesh Interface, direct access to basic data. */
#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); \
static int mesh_render_verts_num_get(Mesh *me)
{
return me->edit_btmesh ? me->edit_btmesh->bm->totvert : me->totvert;
}
static int mesh_render_edges_num_get(Mesh *me)
{
return me->edit_btmesh ? me->edit_btmesh->bm->totedge : me->totedge;
}
static int mesh_render_looptri_num_get(Mesh *me)
{
return me->edit_btmesh ? me->edit_btmesh->tottri : poly_to_tri_count(me->totpoly, me->totloop);
}
static int mesh_render_polys_num_get(Mesh *me)
{
return me->edit_btmesh ? me->edit_btmesh->bm->totface : me->totpoly;
}
static int UNUSED_FUNCTION(mesh_render_loops_num_get)(Mesh *me)
{
return me->edit_btmesh ? me->edit_btmesh->bm->totloop : me->totloop;
}
/* ---------------------------------------------------------------------- */
/* 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;
BMEditMesh *edit_bmesh;
MVert *mvert;
MEdge *medge;
MLoop *mloop;
MPoly *mpoly;
/* Data created on-demand (usually not for bmesh-based data). */
EdgeHash *ehash;
EdgeAdjacentPolys *edges_adjacent_polys;
MLoopTri *mlooptri;
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,
};
static MeshRenderData *mesh_render_data_create(Mesh *me, const int types)
{
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;
}
BM_mesh_elem_index_ensure(bm, bm_ensure_types);
BM_mesh_elem_table_ensure(bm, bm_ensure_types & ~BM_LOOP);
}
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);
}
}
/* Mesh Implementation */
static int mesh_struct_get_num_edges(Mesh *me)
{
return me->totedge;
return mrdata;
}
static int mesh_struct_get_num_verts(Mesh *me)
static void mesh_render_data_free(MeshRenderData *mrdata)
{
return me->totvert;
if (mrdata->ehash) {
BLI_edgehash_free(mrdata->ehash, NULL);
}
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 int mesh_struct_get_num_faces(Mesh *me)
static int mesh_render_data_verts_num_get(const MeshRenderData *mrdata)
{
BKE_mesh_tessface_ensure(me);
return me->totface;
BLI_assert(mrdata->types & MR_DATATYPE_VERT);
return mrdata->totvert;
}
static int mesh_struct_get_num_polys(Mesh *me)
static int mesh_render_data_edges_num_get(const MeshRenderData *mrdata)
{
return me->totpoly;
BLI_assert(mrdata->types & MR_DATATYPE_EDGE);
return mrdata->totedge;
}
static int mesh_struct_get_num_loops(Mesh *me)
static int mesh_render_data_looptri_num_get(const MeshRenderData *mrdata)
{
return me->totloop;
BLI_assert(mrdata->types & MR_DATATYPE_LOOPTRI);
return mrdata->tottri;
}
static MEdge *mesh_struct_get_array_edge(Mesh *me)
static int UNUSED_FUNCTION(mesh_render_data_loops_num_get)(const MeshRenderData *mrdata)
{
return CustomData_get_layer(&me->edata, CD_MEDGE);
BLI_assert(mrdata->types & MR_DATATYPE_LOOP);
return mrdata->totloop;
}
static MFace *mesh_struct_get_array_face(Mesh *me)
static int UNUSED_FUNCTION(mesh_render_data_polys_num_get)(const MeshRenderData *mrdata)
{
BKE_mesh_tessface_ensure(me);
return CustomData_get_layer(&me->fdata, CD_MFACE);
BLI_assert(mrdata->types & MR_DATATYPE_POLY);
return mrdata->totpoly;
}
static MLoop *mesh_struct_get_array_loop(Mesh *me)
static float *mesh_render_data_vert_co(const MeshRenderData *mrdata, const int vert_idx)
{
return me->mloop;
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 MPoly *mesh_struct_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])
{
return me->mpoly;
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_struct_get_array_vert(Mesh *me)
static bool mesh_render_data_edge_exists(MeshRenderData *mrdata, const int v1, const int v2)
{
return CustomData_get_layer(&me->vdata, CD_MVERT);
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__);
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;
}
}
/* 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 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)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getNumVerts(dm);
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_bmesh_get_num_edges(Mesh *me)
static void mesh_render_data_looptri_verts_indices_get(const MeshRenderData *mrdata, const int tri_idx, int r_vert_idx[3])
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getNumEdges(dm);
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_bmesh_get_num_faces(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])
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getNumTessFaces(dm);
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_bmesh_get_num_polys(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getNumPolys(dm);
}
static int mesh_bmesh_get_num_loops(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getNumLoops(dm);
}
static MEdge *mesh_bmesh_get_array_edge(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getEdgeArray(dm);
}
static MFace *mesh_bmesh_get_array_face(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getTessFaceArray(dm);
}
static MLoop *mesh_bmesh_get_array_loop(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getLoopArray(dm);
}
static MPoly *mesh_bmesh_get_array_poly(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getPolyArray(dm);
}
static MVert *mesh_bmesh_get_array_vert(Mesh *me)
{
BMEditMesh *bm = me->edit_btmesh;
DerivedMesh *dm = bm->derivedFinal;
return dm->getVertArray(dm);
}
/* Mesh API */
static int mesh_render_get_num_edges(Mesh *me)
{
MESH_RENDER_FUNCTION(get_num_edges);
}
static int mesh_render_get_num_faces(Mesh *me)
{
MESH_RENDER_FUNCTION(get_num_faces);
}
static int mesh_render_get_num_loops(Mesh *me)
{
MESH_RENDER_FUNCTION(get_num_loops);
}
static int mesh_render_get_num_polys(Mesh *me)
{
MESH_RENDER_FUNCTION(get_num_polys);
}
static int mesh_render_get_num_verts(Mesh *me)
{
MESH_RENDER_FUNCTION(get_num_verts);
}
static MEdge *mesh_render_get_array_edge(Mesh *me)
{
MESH_RENDER_FUNCTION(get_array_edge);
}
static MFace *mesh_render_get_array_face(Mesh *me)
{
MESH_RENDER_FUNCTION(get_array_face);
}
static MLoop *mesh_render_get_array_loop(Mesh *me)
{
MESH_RENDER_FUNCTION(get_array_loop);
}
static MPoly *mesh_render_get_array_poly(Mesh *me)
{
MESH_RENDER_FUNCTION(get_array_poly);
}
static MVert *mesh_render_get_array_vert(Mesh *me)
{
MESH_RENDER_FUNCTION(get_array_vert);
}
/* ---------------------------------------------------------------------- */
/* Mesh Batch Cache */
@@ -257,12 +466,14 @@ typedef struct MeshBatchCache {
/* 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;
@@ -282,10 +493,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;
}
@@ -297,13 +508,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;
@@ -312,92 +531,12 @@ 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)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
if (cache->pos_in_order == NULL) {
static VertexFormat format = { 0 };
static unsigned pos_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
}
const int vertex_ct = mesh_render_get_num_verts(me);
const MVert *verts = mesh_render_get_array_vert(me);
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);
}
#endif
}
return cache->pos_in_order;
}
static ElementList *mesh_batch_cache_get_edges_in_order(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
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);
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);
}
cache->edges_in_order = ElementList_build(&elb);
}
return cache->edges_in_order;
}
static ElementList *mesh_batch_cache_get_triangles_in_order(Mesh *me)
{
MeshBatchCache *cache = mesh_batch_cache_get(me);
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);
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);
if (tess->v4) {
add_triangle_vertices(&elb, tess->v1, tess->v3, tess->v4);
}
}
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)
{
MeshBatchCache *cache = me->batch_cache;
@@ -406,7 +545,7 @@ void BKE_mesh_batch_cache_dirty(struct Mesh *me)
}
}
void BKE_mesh_batch_cache_free(Mesh *me)
void BKE_mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->batch_cache;
if (!cache) {
@@ -432,9 +571,82 @@ void BKE_mesh_batch_cache_free(Mesh *me)
if (cache->overlay_edges) {
Batch_discard_all(cache->overlay_edges);
}
}
MEM_freeN(cache);
me->batch_cache = NULL;
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_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;
if (format.attrib_ct == 0) {
/* initialize vertex format */
pos_id = add_attrib(&format, "pos", GL_FLOAT, 3, KEEP_FLOAT);
}
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);
for (int i = 0; i < vertex_ct; ++i) {
setAttrib(cache->pos_in_order, pos_id, i, mesh_render_data_vert_co(mrdata, i));
}
}
return cache->pos_in_order;
}
static ElementList *mesh_batch_cache_get_edges_in_order(MeshRenderData *mrdata, MeshBatchCache *cache)
{
BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_EDGE));
if (cache->edges_in_order == NULL) {
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) {
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);
}
return cache->edges_in_order;
}
static ElementList *mesh_batch_cache_get_triangles_in_order(MeshRenderData *mrdata, MeshBatchCache *cache)
{
BLI_assert(mrdata->types & (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI));
if (cache->triangles_in_order == NULL) {
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, 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);
add_triangle_vertices(&elb, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2]);
}
cache->triangles_in_order = ElementList_build(&elb);
}
return cache->triangles_in_order;
}
Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *me)
@@ -443,7 +655,12 @@ Batch *BKE_mesh_batch_cache_get_all_edges(Mesh *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));
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_in_order(mrdata, cache),
mesh_batch_cache_get_edges_in_order(mrdata, cache));
mesh_render_data_free(mrdata);
}
return cache->all_edges;
@@ -455,7 +672,12 @@ Batch *BKE_mesh_batch_cache_get_all_triangles(Mesh *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));
MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI);
cache->all_triangles = Batch_create(GL_TRIANGLES, mesh_batch_cache_get_pos_in_order(mrdata, cache),
mesh_batch_cache_get_triangles_in_order(mrdata, cache));
mesh_render_data_free(mrdata);
}
return cache->all_triangles;
@@ -467,61 +689,46 @@ Batch *BKE_mesh_batch_cache_get_triangles_with_normals(Mesh *me)
if (cache->triangles_with_normals == NULL) {
unsigned int vidx = 0, nidx = 0;
float face_no[3];
short face_no_short[3];
unsigned int mpoly_prev = UINT_MAX;
static VertexFormat format = { 0 };
static unsigned pos_id, nor_id;
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 MVert *verts = mesh_render_get_array_vert(me);
const MLoop *loops = mesh_render_get_array_loop(me);
const MPoly *polys = mesh_render_get_array_poly(me);
const int totpoly = mesh_render_get_num_polys(me);
const int totloop = mesh_render_get_num_loops(me);
const int tottri = poly_to_tri_count(totpoly,totloop);
MLoopTri *looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
BKE_mesh_recalc_looptri(loops, polys, verts, totloop, totpoly, looptri);
MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
const int tottri = mesh_render_data_looptri_num_get(mrdata);
VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
VertexBuffer_allocate_data(vbo, tottri * 3);
for (int i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &polys[lt->poly];
float *tri_vert_cos[3];
short *tri_nor, *tri_vert_nors[3];
/* Calc Normal */
if (lt->poly != mpoly_prev) {
BKE_mesh_calc_poly_normal(mp, &loops[mp->loopstart], verts, face_no);
mpoly_prev = lt->poly;
}
const bool is_smooth = mesh_render_data_looptri_cos_nors_smooth_get(mrdata, i, &tri_vert_cos, &tri_nor, &tri_vert_nors);
if ((mp->flag & ME_SMOOTH) == 0) {
normal_float_to_short_v3(face_no_short, face_no);
setAttrib(vbo, nor_id, nidx++, face_no_short);
setAttrib(vbo, nor_id, nidx++, face_no_short);
setAttrib(vbo, nor_id, nidx++, face_no_short);
if (is_smooth) {
setAttrib(vbo, nor_id, nidx++, tri_vert_nors[0]);
setAttrib(vbo, nor_id, nidx++, tri_vert_nors[1]);
setAttrib(vbo, nor_id, nidx++, tri_vert_nors[2]);
}
else {
setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[0]].v].no);
setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[1]].v].no);
setAttrib(vbo, nor_id, nidx++, &verts[loops[lt->tri[2]].v].no);
setAttrib(vbo, nor_id, nidx++, tri_nor);
setAttrib(vbo, nor_id, nidx++, tri_nor);
setAttrib(vbo, nor_id, nidx++, tri_nor);
}
setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[0]].v].co);
setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[1]].v].co);
setAttrib(vbo, pos_id, vidx++, &verts[loops[lt->tri[2]].v].co);
setAttrib(vbo, pos_id, vidx++, tri_vert_cos[0]);
setAttrib(vbo, pos_id, vidx++, tri_vert_cos[1]);
setAttrib(vbo, pos_id, vidx++, tri_vert_cos[2]);
}
cache->triangles_with_normals = Batch_create(GL_TRIANGLES, vbo, NULL);
MEM_freeN(looptri);
mesh_render_data_free(mrdata);
}
return cache->triangles_with_normals;
@@ -533,8 +740,12 @@ 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);
MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT);
cache->all_verts = Batch_create(GL_POINTS, mesh_batch_cache_get_pos_in_order(mrdata, cache), NULL);
Batch_set_builtin_program(cache->all_verts, GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR);
mesh_render_data_free(mrdata);
}
return cache->all_verts;
@@ -547,7 +758,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);
@@ -562,48 +773,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);
MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOP | MR_DATATYPE_POLY);
/* 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");
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;
@@ -612,59 +799,44 @@ 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)
{
/* TODO: same thing, except not ridiculously slow */
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;
}
}
return false;
}
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)
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 base_vert_idx)
{
const float edgeMods[2] = { 0.0f, 1.0f };
const float *pos = verts[v1].co;
const float *pos = mesh_render_data_vert_co(mrdata, v1);
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));
setAttrib(vbo, edgeMod_id, base_vert_idx + 0, edgeMods + (mesh_render_data_edge_exists(mrdata, v2, v3) ? 1 : 0));
pos = verts[v2].co;
pos = mesh_render_data_vert_co(mrdata, v2);
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));
setAttrib(vbo, edgeMod_id, base_vert_idx + 1, edgeMods + (mesh_render_data_edge_exists(mrdata, v3, v1) ? 1 : 0));
pos = verts[v3].co;
pos = mesh_render_data_vert_co(mrdata, v3);
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));
setAttrib(vbo, edgeMod_id, base_vert_idx + 2, edgeMods + (mesh_render_data_edge_exists(mrdata, v1, v2) ? 1 : 0));
}
Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me)
@@ -672,9 +844,9 @@ Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
if (cache->overlay_edges == NULL) {
/* create batch from DM */
/* create batch from mesh */
static VertexFormat format = { 0 };
static unsigned pos_id, edgeMod_id;
static unsigned int pos_id, edgeMod_id;
if (format.attrib_ct == 0) {
/* initialize vertex format */
@@ -683,32 +855,22 @@ Batch *BKE_mesh_batch_cache_get_overlay_edges(Mesh *me)
}
VertexBuffer *vbo = VertexBuffer_create_with_format(&format);
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);
MeshRenderData *mrdata = mesh_render_data_create(me, MR_DATATYPE_VERT | MR_DATATYPE_EDGE | MR_DATATYPE_LOOPTRI);
const int tri_ct = mesh_render_data_looptri_num_get(mrdata);
VertexBuffer_allocate_data(vbo, tessface_ct * 6); /* up to 2 triangles per tessface */
VertexBuffer_allocate_data(vbo, tri_ct * 3);
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);
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, edgeMod_id, tri_vert_idx[0], tri_vert_idx[1], tri_vert_idx[2], 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;
}
}
/* 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);
}
cache->overlay_edges = Batch_create(GL_TRIANGLES, vbo, NULL);
mesh_render_data_free(mrdata);
}
return cache->overlay_edges;