Sculpt dyntopo: Add support for multiple materials to dyntopo

pbvh drawing.

* Dyntopo now stores a list of PBVHTriBufs in leaf nodes, one per material
  used by the node.
* Actual drawing buffers live in a new mat_draw_buffers PBVHNode member.
This commit is contained in:
Joseph Eagar 2021-07-02 13:14:00 -07:00
parent d0759840a0
commit 57286eed8d
6 changed files with 548 additions and 291 deletions

View File

@ -64,10 +64,11 @@ typedef struct PBVHTriBuf {
PBVHTri *tris;
SculptVertRef *verts;
int tottri, totvert;
int tris_size, verts_size;
// private field
intptr_t *loops;
int totloop;
int totloop, mat_nr;
float min[3], max[3];
} PBVHTriBuf;
@ -703,7 +704,7 @@ bool BKE_pbvh_curvature_update_get(PBVHNode *node);
int BKE_pbvh_get_totnodes(PBVH *pbvh);
void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);

View File

@ -705,9 +705,8 @@ void BKE_pbvh_free(PBVH *pbvh)
PBVHNode *node = &pbvh->nodes[i];
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers) {
GPU_pbvh_buffers_free(node->draw_buffers);
}
pbvh_free_all_draw_buffers(node);
if (node->vert_indices) {
MEM_freeN((void *)node->vert_indices);
}
@ -1320,10 +1319,23 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
node->totprim,
pbvh->mesh);
break;
case PBVH_BMESH:
node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
case PBVH_BMESH: {
BKE_pbvh_bmesh_check_tris(pbvh, node);
node->tot_mat_draw_buffers = node->tot_tri_buffers;
if (node->tot_tri_buffers) {
node->mat_draw_buffers = MEM_malloc_arrayN(
node->tot_tri_buffers, sizeof(void *), "node->mat_draw_buffers");
}
for (int i = 0; i < node->tot_tri_buffers; i++) {
node->mat_draw_buffers[i] = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
}
break;
}
}
}
@ -1357,19 +1369,41 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
update_flags);
break;
case PBVH_BMESH:
BKE_pbvh_bmesh_check_tris(pbvh, node);
GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
node->tribuf,
update_flags,
pbvh->cd_vert_node_offset,
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
data->flat_vcol_shading,
data->active_vcol_only);
if (BKE_pbvh_bmesh_check_tris(pbvh, node)) {
pbvh_free_all_draw_buffers(node);
node->tot_mat_draw_buffers = node->tot_tri_buffers;
if (node->tot_tri_buffers) {
node->mat_draw_buffers = MEM_malloc_arrayN(
node->tot_tri_buffers, sizeof(void *), "node->mat_draw_buffers");
for (int i = 0; i < node->tot_tri_buffers; i++) {
node->mat_draw_buffers[i] = GPU_pbvh_bmesh_buffers_build(
pbvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
}
}
}
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
if (i >= node->tot_tri_buffers) {
printf("pbvh corruption!\n");
continue;
}
GPU_pbvh_bmesh_buffers_update(node->mat_draw_buffers[i],
pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts,
node->tri_buffers + i,
update_flags,
pbvh->cd_vert_node_offset,
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
data->flat_vcol_shading,
data->active_vcol_only,
node->tri_buffers[i].mat_nr);
}
break;
}
}
@ -1392,6 +1426,36 @@ void BKE_pbvh_set_flat_vcol_shading(PBVH *pbvh, bool value)
pbvh->flat_vcol_shading = value;
}
void pbvh_free_all_draw_buffers(PBVHNode *node)
{
if (node->draw_buffers) {
GPU_pbvh_buffers_free(node->draw_buffers);
node->draw_buffers = NULL;
}
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
GPU_pbvh_buffers_free(node->mat_draw_buffers[i]);
}
MEM_SAFE_FREE(node->mat_draw_buffers);
node->mat_draw_buffers = NULL;
node->tot_mat_draw_buffers = 0;
}
void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node)
{
if (pbvh->type == PBVH_GRIDS) {
GPU_pbvh_grid_buffers_update_free(
node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
}
else if (pbvh->type == PBVH_BMESH) {
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
GPU_pbvh_bmesh_buffers_update_free(node->mat_draw_buffers[i]);
}
}
}
static void pbvh_update_draw_buffers(
PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag, bool active_vcol_only)
{
@ -1400,17 +1464,10 @@ static void pbvh_update_draw_buffers(
for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
GPU_pbvh_buffers_free(node->draw_buffers);
node->draw_buffers = NULL;
pbvh_free_all_draw_buffers(node);
}
else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) {
if (pbvh->type == PBVH_GRIDS) {
GPU_pbvh_grid_buffers_update_free(
node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices);
}
else if (pbvh->type == PBVH_BMESH) {
GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers);
}
else if ((node->flag & PBVH_UpdateDrawBuffers)) {
pbvh_update_free_all_draw_buffers(pbvh, node);
}
}
}
@ -1449,7 +1506,13 @@ static void pbvh_update_draw_buffers(
if (node->flag & PBVH_UpdateDrawBuffers) {
/* Flush buffers uses OpenGL, so not in parallel. */
GPU_pbvh_buffers_update_flush(node->draw_buffers);
if (node->draw_buffers) {
GPU_pbvh_buffers_update_flush(node->draw_buffers);
}
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
GPU_pbvh_buffers_update_flush(node->mat_draw_buffers[i]);
}
}
node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers);
@ -2898,7 +2961,13 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
for (int i = 0; i < totnode; i++) {
PBVHNode *node = nodes[i];
if (!(node->flag & PBVH_FullyHidden)) {
draw_fn(user_data, node->draw_buffers);
if (node->draw_buffers) {
draw_fn(user_data, node->draw_buffers);
}
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
draw_fn(user_data, node->mat_draw_buffers[i]);
}
}
}

View File

@ -53,6 +53,8 @@ Topology rake:
#include "PIL_time.h"
#include "atomic_ops.h"
#include "DNA_material_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_ccg.h"
#include "BKE_pbvh.h"
@ -506,10 +508,7 @@ static void pbvh_bmesh_node_split(
n->bm_other_verts = NULL;
n->layer_disp = NULL;
if (n->draw_buffers) {
GPU_pbvh_buffers_free(n->draw_buffers);
n->draw_buffers = NULL;
}
pbvh_free_all_draw_buffers(n);
n->flag &= ~PBVH_Leaf;
/* Recurse */
@ -3999,6 +3998,20 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
static void pbvh_free_tribuf(PBVHTriBuf *tribuf)
{
MEM_SAFE_FREE(tribuf->verts);
MEM_SAFE_FREE(tribuf->tris);
MEM_SAFE_FREE(tribuf->loops);
tribuf->verts = NULL;
tribuf->tris = NULL;
tribuf->loops = NULL;
tribuf->verts_size = 0;
tribuf->tris_size = 0;
}
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node)
{
BKE_pbvh_bmesh_check_tris(pbvh, node);
@ -4009,12 +4022,21 @@ PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node)
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node)
{
if (node->tribuf) {
MEM_SAFE_FREE(node->tribuf->verts);
MEM_SAFE_FREE(node->tribuf->tris);
MEM_SAFE_FREE(node->tribuf->loops);
pbvh_free_tribuf(node->tribuf);
MEM_freeN(node->tribuf);
node->tribuf = NULL;
}
if (node->tri_buffers) {
for (int i = 0; i < node->tot_tri_buffers; i++) {
pbvh_free_tribuf(node->tri_buffers + i);
}
MEM_SAFE_FREE(node->tri_buffers);
node->tri_buffers = NULL;
node->tot_tri_buffers = 0;
}
}
/*
@ -4138,41 +4160,87 @@ static bool pbvh_bmesh_split_tris(PBVH *pbvh, PBVHNode *node)
return true;
}
ATTR_NO_OPT BLI_INLINE PBVHTri *pbvh_tribuf_add_tri(PBVHTriBuf *tribuf)
{
tribuf->tottri++;
if (tribuf->tottri >= tribuf->tris_size) {
size_t newsize = (size_t)32 + (size_t)tribuf->tris_size + (size_t)(tribuf->tris_size >> 1);
if (!tribuf->tris) {
tribuf->tris = MEM_mallocN(sizeof(*tribuf->tris) * newsize, "tribuf tris");
}
else {
tribuf->tris = MEM_reallocN_id(tribuf->tris, sizeof(*tribuf->tris) * newsize, "tribuf tris");
}
tribuf->tris_size = newsize;
}
return tribuf->tris + tribuf->tottri - 1;
}
ATTR_NO_OPT BLI_INLINE void pbvh_tribuf_add_vert(PBVHTriBuf *tribuf, SculptVertRef vertex)
{
tribuf->totvert++;
if (tribuf->totvert >= tribuf->verts_size) {
size_t newsize = (size_t)32 + (size_t)(tribuf->verts_size << 1);
if (!tribuf->verts) {
tribuf->verts = MEM_mallocN(sizeof(*tribuf->verts) * newsize, "tribuf verts");
}
else {
tribuf->verts = MEM_reallocN_id(
tribuf->verts, sizeof(*tribuf->verts) * newsize, "tribuf verts");
}
tribuf->verts_size = newsize;
}
tribuf->verts[tribuf->totvert - 1] = vertex;
}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
*
* Skips triangles that are hidden. */
void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
ATTR_NO_OPT bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
{
BMesh *bm = pbvh->bm;
if (!(node->flag & PBVH_UpdateTris) && node->tribuf) {
return;
return false;
}
GHash *vmap = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
GHash *mat_vmaps[MAXMAT];
int mat_map[MAXMAT];
for (int i = 0; i < MAXMAT; i++) {
mat_map[i] = -1;
mat_vmaps[i] = NULL;
}
if (node->tribuf) {
MEM_SAFE_FREE(node->tribuf->verts);
MEM_SAFE_FREE(node->tribuf->tris);
MEM_SAFE_FREE(node->tribuf->loops);
node->tribuf->tottri = 0;
node->tribuf->totvert = 0;
node->tribuf->totloop = 0;
pbvh_free_tribuf(node->tribuf);
}
else {
node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
node->tribuf->loops = NULL;
node->tribuf->totloop = 0;
}
PBVHTriBuf *tribufs = NULL; // material-specific tribuffers
BLI_array_declare(tribufs);
node->tribuf->mat_nr = 0;
node->tribuf->tottri = 0;
node->tribuf->totvert = 0;
node->tribuf->totloop = 0;
node->flag &= ~PBVH_UpdateTris;
PBVHTri *tris = NULL;
SculptVertRef *verts = NULL;
BLI_array_declare(tris);
BLI_array_declare(verts);
GHash *vmap = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
BMFace *f;
float min[3], max[3];
@ -4180,7 +4248,26 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
INIT_MINMAX(min, max);
TGSET_ITER (f, node->bm_faces) {
PBVHTri tri = {0};
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
const int mat_nr = f->mat_nr;
if (mat_map[mat_nr] == -1) {
PBVHTriBuf _tribuf = {0};
_tribuf.mat_nr = mat_nr;
mat_map[mat_nr] = BLI_array_len(tribufs);
mat_vmaps[mat_nr] = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
BLI_array_append(tribufs, _tribuf);
}
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
BMLoop *l = f->l_first;
int j = 0;
@ -4193,11 +4280,23 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
minmax_v3v3_v3(min, max, l->v->co);
*val = (void *)BLI_array_len(verts);
BLI_array_append(verts, sv);
*val = (void *)node->tribuf->totvert;
pbvh_tribuf_add_vert(node->tribuf, sv);
}
tri.v[j] = (intptr_t)val[0];
tri->v[j] = (intptr_t)val[0];
val = NULL;
if (!BLI_ghash_ensure_p(mat_vmaps[mat_nr], l->v, &val)) {
SculptVertRef sv = {(intptr_t)l->v};
minmax_v3v3_v3(min, max, l->v->co);
*val = (void *)mat_tribuf->totvert;
pbvh_tribuf_add_vert(mat_tribuf, sv);
}
mat_tri->v[j] = (intptr_t)val[0];
j++;
@ -4208,19 +4307,15 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
l = l->next;
} while (l != f->l_first);
copy_v3_v3(tri.no, f->no);
tri.f.i = (intptr_t)f;
BLI_array_append(tris, tri);
copy_v3_v3(tri->no, f->no);
tri->f.i = (intptr_t)f;
}
TGSET_ITER_END
bm->elem_index_dirty |= BM_VERT;
node->tribuf->tris = tris;
node->tribuf->tottri = BLI_array_len(tris);
node->tribuf->verts = verts;
node->tribuf->totvert = BLI_array_len(verts);
node->tri_buffers = tribufs;
node->tot_tri_buffers = BLI_array_len(tribufs);
if (node->tribuf->totvert) {
copy_v3_v3(node->tribuf->min, min);
@ -4232,6 +4327,13 @@ void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
}
BLI_ghash_free(vmap, NULL, NULL);
for (int i = 0; i < MAXMAT; i++) {
if (mat_vmaps[i]) {
BLI_ghash_free(mat_vmaps[i], NULL, NULL);
}
}
return true;
}
static int pbvh_count_subtree_verts(PBVH *pbvh, PBVHNode *n)
@ -4322,7 +4424,8 @@ static void BKE_pbvh_bmesh_correct_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *pa
BMVert *v;
node->children_offset = 0;
node->draw_buffers = NULL;
pbvh_free_all_draw_buffers(node);
// rebuild bm_other_verts
BMFace *f;
@ -4433,10 +4536,9 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
MEM_freeN(n->layer_disp);
n->layer_disp = NULL;
}
if (n->draw_buffers) {
GPU_pbvh_buffers_free(n->draw_buffers);
n->draw_buffers = NULL;
}
pbvh_free_all_draw_buffers(n);
if (n->vert_indices) {
MEM_freeN((void *)n->vert_indices);
n->vert_indices = NULL;
@ -5188,7 +5290,8 @@ BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh)
f1->head.index = f2->head.index = BLI_array_len(faces);
BLI_array_append(faces, f2);
// CustomData_bmesh_copy_data(&pbvh->bm->pdata, &bm2->pdata, f1->head.data, &f2->head.data);
// CustomData_bmesh_copy_data(&pbvh->bm->pdata, &bm2->pdata, f1->head.data,
// &f2->head.data);
BM_elem_attrs_copy_ex(pbvh->bm, bm2, f1, f2, 0, 0L);
BMLoop *l2 = f2->l_first;

View File

@ -17,6 +17,7 @@
#pragma once
#include "BLI_ghash.h"
#include "DNA_material_types.h"
/** \file
* \ingroup bli
@ -37,6 +38,8 @@ typedef struct {
struct PBVHNode {
/* Opaque handle for drawing code */
struct GPU_PBVH_Buffers *draw_buffers;
struct GPU_PBVH_Buffers **mat_draw_buffers; // currently only used by pbvh_bmesh
int tot_mat_draw_buffers;
int id;
@ -107,7 +110,9 @@ struct PBVHNode {
TableGSet *bm_unique_verts;
TableGSet *bm_other_verts;
PBVHTriBuf *tribuf;
PBVHTriBuf *tribuf; // all triangles
PBVHTriBuf *tri_buffers; // tribuffers, one per material used
int tot_tri_buffers;
int updategen;
@ -259,3 +264,6 @@ bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
int stroke_id);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
void pbvh_free_all_draw_buffers(PBVHNode *node);
void pbvh_update_free_all_draw_buffers(PBVH *pbvh, PBVHNode *node);

View File

@ -104,7 +104,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only);
bool active_vcol_only,
short mat_nr);
void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,

View File

@ -1131,13 +1131,13 @@ static int gpu_bmesh_vert_visible_count(TableGSet *bm_unique_verts, TableGSet *b
}
/* Return the total number of visible faces */
static int gpu_bmesh_face_visible_count(TableGSet *bm_faces)
static int gpu_bmesh_face_visible_count(TableGSet *bm_faces, int mat_nr)
{
int totface = 0;
BMFace *f;
TGSET_ITER (f, bm_faces) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN) && f->mat_nr == mat_nr) {
totface++;
}
}
@ -1394,7 +1394,8 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool active_vcol_only)
bool active_vcol_only,
short mat_nr)
{
const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV);
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
@ -1415,9 +1416,7 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
&bm->vdata, cd_vcols, cd_vcol_layers, active_vcol_only);
/* Count visible triangles */
tottri = gpu_bmesh_face_visible_count(bm_faces) * 6;
// XXX disable indexed verts for now
tottri = gpu_bmesh_face_visible_count(bm_faces, mat_nr) * 6;
totvert = tottri * 3;
if (!tottri) {
@ -1452,6 +1451,10 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
TGSET_ITER (f, bm_faces) {
if (f->mat_nr != mat_nr) {
continue;
}
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
@ -1556,44 +1559,28 @@ static void GPU_pbvh_bmesh_buffers_update_flat_vcol(GPU_PBVH_Buffers *buffers,
buffers->tot_tri = tottri;
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->material_index = mat_nr;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer.
* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
TableGSet *bm_faces,
TableGSet *bm_unique_verts,
TableGSet *bm_other_verts,
PBVHTriBuf *tribuf,
const int update_flags,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only)
static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
BMesh *bm,
TableGSet *bm_faces,
TableGSet *bm_unique_verts,
TableGSet *bm_other_verts,
PBVHTriBuf *tribuf,
const int update_flags,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only,
short mat_nr)
{
if (flat_vcol && CustomData_has_layer(&bm->vdata, CD_PROP_COLOR)) {
GPU_pbvh_bmesh_buffers_update_flat_vcol(buffers,
bm,
bm_faces,
bm_unique_verts,
bm_other_verts,
update_flags,
cd_vert_node_offset,
face_sets_color_seed,
face_sets_color_default,
active_vcol_only);
return;
}
const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV);
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
@ -1613,16 +1600,10 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
&bm->vdata, cd_vcols, cd_vcol_layers, active_vcol_only);
/* Count visible triangles */
const bool indexed = buffers->smooth && tribuf && !have_uv;
tottri = indexed ? tribuf->tottri : gpu_bmesh_face_visible_count(bm_faces);
tottri = tribuf->tottri;
if (indexed) {
/* Count visible vertices */
totvert = tribuf->totvert;
}
else {
totvert = tottri * 3;
}
/* Count visible vertices */
totvert = tribuf->totvert;
if (!tottri) {
if (BLI_table_gset_len(bm_faces) != 0) {
@ -1650,230 +1631,324 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
int v_index = 0;
if (indexed) {
/* Fill the vertex and triangle buffer in one pass over faces. */
GPUIndexBufBuilder elb, elb_lines;
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
/* Fill the vertex and triangle buffer in one pass over faces. */
GPUIndexBufBuilder elb, elb_lines;
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert);
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert);
GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert);
BMFace *f;
GPUVertBuf *vert_buf = buffers->vert_buf;
GPUVertBuf *vert_buf = buffers->vert_buf;
#ifdef QUANTIZED_PERF_TEST
float min[3];
float max[3];
float mat[4][4];
float imat[4][4];
float scale[3];
float min[3];
float max[3];
float mat[4][4];
float imat[4][4];
float scale[3];
INIT_MINMAX(min, max);
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
INIT_MINMAX(min, max);
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
minmax_v3v3_v3(min, max, v->co);
}
minmax_v3v3_v3(min, max, v->co);
}
sub_v3_v3v3(scale, max, min);
sub_v3_v3v3(scale, max, min);
scale[0] = scale[0] != 0.0f ? 1.0f / scale[0] : 0.0f;
scale[1] = scale[1] != 0.0f ? 1.0f / scale[1] : 0.0f;
scale[2] = scale[2] != 0.0f ? 1.0f / scale[2] : 0.0f;
scale[0] = scale[0] != 0.0f ? 1.0f / scale[0] : 0.0f;
scale[1] = scale[1] != 0.0f ? 1.0f / scale[1] : 0.0f;
scale[2] = scale[2] != 0.0f ? 1.0f / scale[2] : 0.0f;
memset((float *)mat, 0, sizeof(float) * 16);
memset((float *)mat, 0, sizeof(float) * 16);
mat[0][0] = scale[0];
mat[1][1] = scale[1];
mat[2][2] = scale[2];
mat[0][0] = scale[0];
mat[1][1] = scale[1];
mat[2][2] = scale[2];
mat[3][0] = -min[0] * scale[0];
mat[3][1] = -min[1] * scale[1];
mat[3][2] = -min[2] * scale[2];
mat[3][0] = -min[0] * scale[0];
mat[3][1] = -min[1] * scale[1];
mat[3][2] = -min[2] * scale[2];
mat[3][3] = 1.0f;
mat[3][3] = 1.0f;
invert_m4_m4(imat, mat);
invert_m4_m4(imat, mat);
#endif
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
for (int i = 0; i < tribuf->totvert; i++) {
BMVert *v = (BMVert *)tribuf->verts[i].i;
#ifdef QUANTIZED_PERF_TEST
float co[3];
copy_v3_v3(co, v->co);
mul_v3_m4v3(co, mat, co);
// sub_v3_v3(co, tribuf->min);
// mul_v3_v3(co, scale);
float co[3];
copy_v3_v3(co, v->co);
mul_v3_m4v3(co, mat, co);
// sub_v3_v3(co, tribuf->min);
// mul_v3_v3(co, scale);
// normal_float_to_short_
unsigned short co_short[3];
co_short[0] = (unsigned short)(co[0] * 65535.0f);
co_short[1] = (unsigned short)(co[1] * 65535.0f);
co_short[2] = (unsigned short)(co[2] * 65535.0f);
// normal_float_to_short_
unsigned short co_short[3];
co_short[0] = (unsigned short)(co[0] * 65535.0f);
co_short[1] = (unsigned short)(co[1] * 65535.0f);
co_short[2] = (unsigned short)(co[2] * 65535.0f);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, i, co_short);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, i, co_short);
signed char no_short[3];
// normal_float_to_short_v3(no_short, v->no);
no_short[0] = (signed char)(v->no[0] * 127.0f);
no_short[1] = (signed char)(v->no[1] * 127.0f);
no_short[2] = (signed char)(v->no[2] * 127.0f);
signed char no_short[3];
// normal_float_to_short_v3(no_short, v->no);
no_short[0] = (signed char)(v->no[0] * 127.0f);
no_short[1] = (signed char)(v->no[1] * 127.0f);
no_short[2] = (signed char)(v->no[2] * 127.0f);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, i, no_short);
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, i, no_short);
#else
gpu_bmesh_vert_to_buffer_copy(v,
buffers->vert_buf,
i,
NULL,
NULL,
cd_vert_mask_offset,
cd_vert_node_offset,
show_mask,
show_vcol,
&empty_mask,
cd_vcols,
cd_vcol_count);
gpu_bmesh_vert_to_buffer_copy(v,
buffers->vert_buf,
i,
NULL,
NULL,
cd_vert_mask_offset,
cd_vert_node_offset,
show_mask,
show_vcol,
&empty_mask,
cd_vcols,
cd_vcol_count);
#endif
}
}
for (int i = 0; i < tribuf->tottri; i++) {
PBVHTri *tri = tribuf->tris + i;
for (int i = 0; i < tribuf->tottri; i++) {
PBVHTri *tri = tribuf->tris + i;
GPU_indexbuf_add_tri_verts(&elb, tri->v[0], tri->v[1], tri->v[2]);
GPU_indexbuf_add_tri_verts(&elb, tri->v[0], tri->v[1], tri->v[2]);
#ifndef QUANTIZED_PERF_TEST
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[0], tri->v[1]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[1], tri->v[2]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[2], tri->v[0]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[0], tri->v[1]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[1], tri->v[2]);
GPU_indexbuf_add_line_verts(&elb_lines, tri->v[2], tri->v[0]);
#endif
}
}
buffers->tot_tri = tottri;
buffers->tot_tri = tottri;
if (buffers->index_buf == NULL) {
buffers->index_buf = GPU_indexbuf_build(&elb);
}
else {
GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
#ifdef QUANTIZED_PERF_TEST
copy_m4_m4(buffers->matrix, imat);
#endif
if (buffers->index_buf == NULL) {
buffers->index_buf = GPU_indexbuf_build(&elb);
}
else {
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
BMFace *f;
GPU_indexbuf_build_in_place(&elb, buffers->index_buf);
}
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
TGSET_ITER (f, bm_faces) {
BLI_assert(f->len == 3);
buffers->material_index = mat_nr;
buffers->show_overlay = !empty_mask || !default_face_set;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
BMLoop *l[3] = {f->l_first, f->l_first->next, f->l_first->prev};
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
float fmask = 0.0f;
int i;
#ifdef QUANTIZED_PERF_TEST
copy_m4_m4(buffers->matrix, imat);
#endif
}
BM_face_as_array_vert_tri(f, v);
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer.
* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
TableGSet *bm_faces,
TableGSet *bm_unique_verts,
TableGSet *bm_other_verts,
PBVHTriBuf *tribuf,
const int update_flags,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only,
short mat_nr)
{
/* Average mask value */
for (i = 0; i < 3; i++) {
fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
}
fmask /= 3.0f;
if (flat_vcol && CustomData_has_layer(&bm->vdata, CD_PROP_COLOR)) {
GPU_pbvh_bmesh_buffers_update_flat_vcol(buffers,
bm,
bm_faces,
bm_unique_verts,
bm_other_verts,
update_flags,
cd_vert_node_offset,
face_sets_color_seed,
face_sets_color_default,
active_vcol_only,
mat_nr);
return;
}
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
const bool have_uv = CustomData_has_layer(&bm->ldata, CD_MLOOPUV);
const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
const bool show_face_sets = CustomData_has_layer(&bm->pdata, CD_SCULPT_FACE_SETS) &&
(update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0;
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
int tottri, totvert;
bool empty_mask = true;
BMFace *f = NULL;
int cd_vcol_offset = CustomData_get_offset(&bm->vdata, CD_PROP_COLOR);
int cd_fset_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS);
if (show_face_sets && cd_fset_offset >= 0) {
const int fset = BM_ELEM_CD_GET_INT(f, cd_fset_offset);
int cd_vcols[MAX_MCOL];
int cd_vcol_layers[MAX_MCOL];
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
default_face_set = false;
}
}
int cd_vcol_count = gpu_pbvh_bmesh_make_vcol_offs(
&bm->vdata, cd_vcols, cd_vcol_layers, active_vcol_only);
for (i = 0; i < 3; i++) {
float *no = buffers->smooth ? v[i]->no : f->no;
/* Count visible triangles */
if (buffers->smooth && !have_uv) {
GPU_pbvh_bmesh_buffers_update_indexed(buffers,
bm,
bm_faces,
bm_unique_verts,
bm_other_verts,
tribuf,
update_flags,
cd_vert_node_offset,
face_sets_color_seed,
face_sets_color_default,
flat_vcol,
active_vcol_only,
mat_nr);
return;
}
gpu_bmesh_vert_to_buffer_copy(v[i],
buffers->vert_buf,
v_index,
no,
&fmask,
cd_vert_mask_offset,
cd_vert_node_offset,
show_mask,
false,
&empty_mask,
NULL,
0);
tottri = gpu_bmesh_face_visible_count(bm_faces, mat_nr);
totvert = tottri * 3;
if (cd_vcol_count >= 0) {
for (int j = 0; j < cd_vcol_count; j++) {
MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[i]->v, cd_vcols[j]);
ushort vcol[4];
if (!tottri) {
/* empty node (i.e. not just hidden)? */
if (!BLI_table_gset_len(bm_faces) != 0) {
buffers->clear_bmesh_on_flush = true;
}
// printf(
// "%.2f %.2f %.2f %.2f\n", mp->color[0], mp->color[1], mp->color[2],
// mp->color[3]);
vcol[0] = unit_float_to_ushort_clamp(mp->color[0]);
vcol[1] = unit_float_to_ushort_clamp(mp->color[1]);
vcol[2] = unit_float_to_ushort_clamp(mp->color[2]);
vcol[3] = unit_float_to_ushort_clamp(mp->color[3]);
buffers->tot_tri = 0;
return;
}
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[j], v_index, vcol);
}
}
else if (cd_mcol_offset >= 0) {
ushort vcol[4];
/* TODO, make mask layer optional for bmesh buffer */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
const int cd_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l[i], cd_mcol_offset);
bool default_face_set = true;
vcol[0] = ml->r * 257;
vcol[1] = ml->g * 257;
vcol[2] = ml->b * 257;
vcol[3] = ml->a * 257;
/* Fill vertex buffer */
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
/* Memory map failed */
return;
}
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], v_index, vcol);
}
int v_index = 0;
if (have_uv) {
MLoopUV *mu = BM_ELEM_CD_GET_VOID_P(l[i], cd_uv_offset);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv);
}
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color);
TGSET_ITER (f, bm_faces) {
BLI_assert(f->len == 3);
if (f->mat_nr != mat_nr) {
continue;
}
v_index++;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v[3];
BMLoop *l[3] = {f->l_first, f->l_first->next, f->l_first->prev};
float fmask = 0.0f;
int i;
BM_face_as_array_vert_tri(f, v);
/* Average mask value */
for (i = 0; i < 3; i++) {
fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
}
fmask /= 3.0f;
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (show_face_sets && cd_fset_offset >= 0) {
const int fset = BM_ELEM_CD_GET_INT(f, cd_fset_offset);
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
default_face_set = false;
}
}
for (i = 0; i < 3; i++) {
float *no = buffers->smooth ? v[i]->no : f->no;
gpu_bmesh_vert_to_buffer_copy(v[i],
buffers->vert_buf,
v_index,
no,
&fmask,
cd_vert_mask_offset,
cd_vert_node_offset,
show_mask,
false,
&empty_mask,
NULL,
0);
if (cd_vcol_count >= 0) {
for (int j = 0; j < cd_vcol_count; j++) {
MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[i]->v, cd_vcols[j]);
ushort vcol[4];
// printf(
// "%.2f %.2f %.2f %.2f\n", mp->color[0], mp->color[1], mp->color[2],
// mp->color[3]);
vcol[0] = unit_float_to_ushort_clamp(mp->color[0]);
vcol[1] = unit_float_to_ushort_clamp(mp->color[1]);
vcol[2] = unit_float_to_ushort_clamp(mp->color[2]);
vcol[3] = unit_float_to_ushort_clamp(mp->color[3]);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[j], v_index, vcol);
}
}
else if (cd_mcol_offset >= 0) {
ushort vcol[4];
MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l[i], cd_mcol_offset);
vcol[0] = ml->r * 257;
vcol[1] = ml->g * 257;
vcol[2] = ml->b * 257;
vcol[3] = ml->a * 257;
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], v_index, vcol);
}
if (have_uv) {
MLoopUV *mu = BM_ELEM_CD_GET_VOID_P(l[i], cd_uv_offset);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv);
}
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color);
v_index++;
}
}
TGSET_ITER_END
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
/* Get material index from the last face we iterated on. */
buffers->material_index = (f) ? f->mat_nr : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
TGSET_ITER_END
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;
/* Get material index from the last face we iterated on. */
buffers->material_index = mat_nr;
buffers->show_overlay = !empty_mask || !default_face_set;
gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS);
}
/* -------------------------------------------------------------------- */