Sculpt dyntopo: Removed triangle limit for PBVH_BMESH
* PBVH_BMESH now supports faces other then triangles; * Dyntopo triangulates faces as it finds them. - I looked into methods of preserving quads and failed to find anything that worked well in practice; it actually worked better to use topology rake to align triangles into quads and then mark diagonal edges for later dissolving then to try to preserve quads explicitly (I've not implementated that here, that was research code). - To avoid excessive cache-destroying loops over vertex-faces, DynTopo flags which verts have non-triangle faces. * PBVHTriBuf now builds edge buffers so we can avoid drawing tesselation phantom edges. * BMLog also now supports arbitrary faces. It still does not support edges though. TODO: * Fix vcol cell shading mode * Make sure indexed drawing works
This commit is contained in:
parent
7cd74015f8
commit
70a4956020
|
@ -54,7 +54,9 @@ BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
|
|||
}
|
||||
|
||||
typedef struct PBVHTri {
|
||||
int v[3]; // references into PBVHTriBuf->verts
|
||||
int v[3]; // references into PBVHTriBuf->verts
|
||||
intptr_t l[3]; // loops
|
||||
int eflag; // bitmask of which edges in the tri are real edges in the mesh
|
||||
|
||||
float no[3];
|
||||
SculptFaceRef f;
|
||||
|
@ -63,8 +65,9 @@ typedef struct PBVHTri {
|
|||
typedef struct PBVHTriBuf {
|
||||
PBVHTri *tris;
|
||||
SculptVertRef *verts;
|
||||
int tottri, totvert;
|
||||
int tris_size, verts_size;
|
||||
int *edges;
|
||||
int totvert, totedge, tottri;
|
||||
int verts_size, edges_size, tris_size;
|
||||
|
||||
// private field
|
||||
intptr_t *loops;
|
||||
|
@ -736,6 +739,8 @@ PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
|
|||
struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
|
||||
void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, struct BMVert *v);
|
||||
|
||||
#define DYNTOPO_DYNAMIC_TESS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_bitmap.h"
|
||||
|
@ -12,6 +13,7 @@
|
|||
#include "BLI_ghash.h"
|
||||
#include "BLI_heap.h"
|
||||
#include "BLI_heap_simple.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_rand.h"
|
||||
|
@ -140,6 +142,9 @@ static void pbvh_bmesh_verify(PBVH *pbvh);
|
|||
} \
|
||||
((void)0)
|
||||
|
||||
static bool check_face_is_tri(PBVH *pbvh, BMFace *f);
|
||||
static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
|
||||
|
||||
BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
|
||||
{
|
||||
float co[3];
|
||||
|
@ -1440,6 +1445,122 @@ static void short_edge_queue_task_cb(void *__restrict userdata,
|
|||
TGSET_ITER_END
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
|
||||
{
|
||||
if (f->len == 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (f->len < 3) {
|
||||
printf("pbvh had < 3 vert face!\n");
|
||||
BKE_pbvh_bmesh_remove_face(pbvh, f, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
BMFace **fs = NULL;
|
||||
BMEdge **es = NULL;
|
||||
LinkNode *dbl = NULL;
|
||||
BLI_array_staticdeclare(fs, 32);
|
||||
BLI_array_staticdeclare(es, 32);
|
||||
|
||||
BKE_pbvh_bmesh_remove_face(pbvh, f, true);
|
||||
|
||||
int len = (f->len - 2) * 3;
|
||||
|
||||
BLI_array_grow_items(fs, len);
|
||||
BLI_array_grow_items(es, len);
|
||||
|
||||
int totface = 0;
|
||||
int totedge = 0;
|
||||
MemArena *arena = NULL;
|
||||
struct Heap *heap = NULL;
|
||||
|
||||
if (f->len > 4) {
|
||||
arena = BLI_memarena_new(512, "ngon arena");
|
||||
heap = BLI_heap_new();
|
||||
}
|
||||
|
||||
BM_face_triangulate(pbvh->bm,
|
||||
f,
|
||||
fs,
|
||||
&totface,
|
||||
es,
|
||||
&totedge,
|
||||
&dbl,
|
||||
MOD_TRIANGULATE_QUAD_FIXED,
|
||||
MOD_TRIANGULATE_NGON_BEAUTY,
|
||||
false,
|
||||
arena,
|
||||
heap);
|
||||
|
||||
while (totface && dbl) {
|
||||
BMFace *f = dbl->link;
|
||||
LinkNode *next = dbl->next;
|
||||
|
||||
for (int i = 0; i < totface; i++) {
|
||||
if (fs[i] == f) {
|
||||
fs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BM_face_kill(pbvh->bm, dbl->link);
|
||||
MEM_freeN(dbl);
|
||||
dbl = next;
|
||||
}
|
||||
|
||||
for (int i = 0; i < totface; i++) {
|
||||
BMFace *f2 = fs[i];
|
||||
|
||||
if (!f2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BKE_pbvh_bmesh_add_face(pbvh, f2, true, true);
|
||||
}
|
||||
|
||||
BKE_pbvh_bmesh_add_face(pbvh, f, true, true);
|
||||
|
||||
BLI_array_free(fs);
|
||||
BLI_array_free(es);
|
||||
|
||||
if (arena) {
|
||||
BLI_memarena_free(arena);
|
||||
}
|
||||
|
||||
if (heap) {
|
||||
BLI_heap_free(heap, NULL);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ATTR_NO_OPT static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v)
|
||||
{
|
||||
BMFace **fs = NULL;
|
||||
BLI_array_staticdeclare(fs, 32);
|
||||
|
||||
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
|
||||
if (!(mv->flag & DYNVERT_NEED_TRIANGULATE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
|
||||
BLI_array_append(fs, f);
|
||||
}
|
||||
|
||||
mv->flag &= ~DYNVERT_NEED_TRIANGULATE;
|
||||
|
||||
for (int i = 0; i < BLI_array_len(fs); i++) {
|
||||
check_face_is_tri(pbvh, fs[i]);
|
||||
}
|
||||
|
||||
BLI_array_free(fs);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create a priority queue containing vertex pairs connected by a long
|
||||
* edge as defined by PBVH.bm_max_edge_len.
|
||||
*
|
||||
|
@ -1681,6 +1802,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
|
|||
{
|
||||
BMesh *bm = pbvh->bm;
|
||||
|
||||
check_vert_fan_are_tris(pbvh, e->v1);
|
||||
check_vert_fan_are_tris(pbvh, e->v2);
|
||||
|
||||
float co_mid[3], no_mid[3];
|
||||
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
|
||||
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
|
||||
|
@ -1968,6 +2092,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
|
|||
{
|
||||
BMVert *v_del, *v_conn;
|
||||
|
||||
check_vert_fan_are_tris(pbvh, e->v1);
|
||||
check_vert_fan_are_tris(pbvh, e->v2);
|
||||
|
||||
// customdata interpolation
|
||||
if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
|
||||
for (int step = 0; step < 2; step++) {
|
||||
|
@ -2409,6 +2536,8 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
continue;
|
||||
}
|
||||
|
||||
check_vert_fan_are_tris(pbvh, v);
|
||||
|
||||
const int val = BM_vert_edge_count(v);
|
||||
if (val != 4 && val != 3) {
|
||||
continue;
|
||||
|
@ -2519,8 +2648,40 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
|
||||
modified = true;
|
||||
|
||||
if (!v->e) {
|
||||
printf("mesh error!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
l = v->e->l;
|
||||
|
||||
bool flipped = false;
|
||||
|
||||
if (val == 4) {
|
||||
// check which quad diagonal to use to split quad
|
||||
// try to preserve hard edges
|
||||
|
||||
float n1[3], n2[3], th1, th2;
|
||||
normal_tri_v3(n1, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co);
|
||||
normal_tri_v3(n2, ls[0]->v->co, ls[2]->v->co, ls[3]->v->co);
|
||||
|
||||
th1 = dot_v3v3(n1, n2);
|
||||
|
||||
normal_tri_v3(n1, ls[1]->v->co, ls[2]->v->co, ls[3]->v->co);
|
||||
normal_tri_v3(n2, ls[1]->v->co, ls[3]->v->co, ls[0]->v->co);
|
||||
|
||||
th2 = dot_v3v3(n1, n2);
|
||||
|
||||
if (th1 > th2) {
|
||||
flipped = true;
|
||||
BMLoop *ls2[4] = {ls[0], ls[1], ls[2], ls[3]};
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ls[j] = ls2[(j + 1) % 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vs[0] = ls[0]->v;
|
||||
vs[1] = ls[1]->v;
|
||||
vs[2] = ls[2]->v;
|
||||
|
@ -2540,11 +2701,15 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
|
|||
vs[1] = ls[2]->v;
|
||||
vs[2] = ls[3]->v;
|
||||
|
||||
BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, v->e->l->f, false, false);
|
||||
BMFace *example = NULL;
|
||||
if (v->e && v->e->l) {
|
||||
example = v->e->l->f;
|
||||
}
|
||||
|
||||
BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, example, false, false);
|
||||
|
||||
CustomData_bmesh_swap_data_simple(
|
||||
&pbvh->bm->ldata, &f2->l_first->prev->head.data, &ls[3]->head.data);
|
||||
|
||||
CustomData_bmesh_copy_data(
|
||||
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &f2->l_first->head.data);
|
||||
CustomData_bmesh_copy_data(
|
||||
|
|
|
@ -1137,7 +1137,8 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
|
|||
MDynTopoVert *mv = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
|
||||
|
||||
BMEdge *e = v->e;
|
||||
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY);
|
||||
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
|
||||
DYNVERT_NEED_TRIANGULATE);
|
||||
|
||||
if (!e) {
|
||||
mv->flag |= DYNVERT_BOUNDARY;
|
||||
|
@ -1155,6 +1156,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
|
|||
mv->flag |= DYNVERT_FSET_BOUNDARY;
|
||||
}
|
||||
|
||||
if (e->l->f->len > 3) {
|
||||
mv->flag |= DYNVERT_NEED_TRIANGULATE;
|
||||
}
|
||||
|
||||
lastfset = fset;
|
||||
first = false;
|
||||
|
||||
|
@ -1163,6 +1168,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
|
|||
if (e->l->radial_next != e->l) {
|
||||
fset = abs(BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset));
|
||||
|
||||
if (e->l->radial_next->f->len > 3) {
|
||||
mv->flag |= DYNVERT_NEED_TRIANGULATE;
|
||||
}
|
||||
|
||||
if (fset != lastfset) {
|
||||
mv->flag |= DYNVERT_FSET_BOUNDARY;
|
||||
}
|
||||
|
@ -1557,11 +1566,35 @@ BLI_INLINE void pbvh_tribuf_add_vert(PBVHTriBuf *tribuf, SculptVertRef vertex)
|
|||
tribuf->verts[tribuf->totvert - 1] = vertex;
|
||||
}
|
||||
|
||||
BLI_INLINE void pbvh_tribuf_add_edge(PBVHTriBuf *tribuf, int v1, int v2)
|
||||
{
|
||||
tribuf->totedge++;
|
||||
|
||||
if (tribuf->totedge >= tribuf->edges_size) {
|
||||
size_t newsize = (size_t)32 + (size_t)(tribuf->edges_size << 1);
|
||||
|
||||
if (!tribuf->edges) {
|
||||
tribuf->edges = MEM_mallocN(sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
|
||||
}
|
||||
else {
|
||||
tribuf->edges = MEM_reallocN_id(
|
||||
tribuf->edges, sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
|
||||
}
|
||||
|
||||
tribuf->edges_size = newsize;
|
||||
}
|
||||
|
||||
int i = (tribuf->totedge - 1) * 2;
|
||||
|
||||
tribuf->edges[i] = v1;
|
||||
tribuf->edges[i + 1] = v2;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
bool 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;
|
||||
|
||||
|
@ -1586,6 +1619,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
|
||||
}
|
||||
|
||||
BMLoop **loops = NULL;
|
||||
uint(*loops_idx)[3] = NULL;
|
||||
|
||||
BLI_array_staticdeclare(loops, 128);
|
||||
BLI_array_staticdeclare(loops_idx, 128);
|
||||
|
||||
PBVHTriBuf *tribufs = NULL; // material-specific tribuffers
|
||||
BLI_array_declare(tribufs);
|
||||
|
||||
|
@ -1593,9 +1632,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
node->tribuf->tottri = 0;
|
||||
node->tribuf->totvert = 0;
|
||||
node->tribuf->totloop = 0;
|
||||
node->tribuf->totedge = 0;
|
||||
|
||||
node->flag &= ~PBVH_UpdateTris;
|
||||
|
||||
const int edgeflag = BM_ELEM_TAG_ALT;
|
||||
|
||||
BMFace *f;
|
||||
|
||||
float min[3], max[3];
|
||||
|
@ -1607,7 +1649,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
continue;
|
||||
}
|
||||
|
||||
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
|
||||
// clear edgeflag for building edge indices later
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
l->e->head.hflag &= ~edgeflag;
|
||||
} while ((l = l->next) != f->l_first);
|
||||
|
||||
const int mat_nr = f->mat_nr;
|
||||
|
||||
if (mat_map[mat_nr] == -1) {
|
||||
|
@ -1621,6 +1668,70 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
BLI_array_append(tribufs, _tribuf);
|
||||
}
|
||||
|
||||
#ifdef DYNTOPO_DYNAMIC_TESS
|
||||
const int tottri = (f->len - 2);
|
||||
|
||||
BLI_array_clear(loops);
|
||||
BLI_array_clear(loops_idx);
|
||||
BLI_array_grow_items(loops, f->len);
|
||||
BLI_array_grow_items(loops_idx, tottri);
|
||||
|
||||
BM_face_calc_tessellation(f, true, loops, loops_idx);
|
||||
|
||||
for (int i = 0; i < tottri; i++) {
|
||||
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
|
||||
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
|
||||
PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
|
||||
|
||||
tri->eflag = mat_tri->eflag = 0;
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
BMLoop *l0 = loops[loops_idx[i][(j + 2) % 3]];
|
||||
BMLoop *l = loops[loops_idx[i][j]];
|
||||
BMLoop *l2 = loops[loops_idx[i][(j + 1) % 3]];
|
||||
|
||||
void **val = NULL;
|
||||
|
||||
bool has_edge = false;
|
||||
|
||||
if (BM_edge_exists(l->v, l2->v)) {
|
||||
tri->eflag |= 1 << j;
|
||||
mat_tri->eflag |= 1 << j;
|
||||
}
|
||||
|
||||
if (!BLI_ghash_ensure_p(vmap, l->v, &val)) {
|
||||
SculptVertRef sv = {(intptr_t)l->v};
|
||||
|
||||
minmax_v3v3_v3(min, max, l->v->co);
|
||||
|
||||
*val = (void *)node->tribuf->totvert;
|
||||
pbvh_tribuf_add_vert(node->tribuf, sv);
|
||||
}
|
||||
|
||||
tri->v[j] = (intptr_t)val[0];
|
||||
tri->l[j] = (intptr_t)l;
|
||||
|
||||
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];
|
||||
mat_tri->l[j] = (intptr_t)l;
|
||||
}
|
||||
|
||||
copy_v3_v3(tri->no, f->no);
|
||||
copy_v3_v3(mat_tri->no, f->no);
|
||||
tri->f.i = (intptr_t)f;
|
||||
mat_tri->f.i = (intptr_t)f;
|
||||
}
|
||||
#else
|
||||
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
|
||||
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
|
||||
PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
|
||||
|
||||
|
@ -1640,6 +1751,7 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
}
|
||||
|
||||
tri->v[j] = (intptr_t)val[0];
|
||||
tri->l[j] = (intptr_t)l;
|
||||
|
||||
val = NULL;
|
||||
if (!BLI_ghash_ensure_p(mat_vmaps[mat_nr], l->v, &val)) {
|
||||
|
@ -1652,6 +1764,7 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
}
|
||||
|
||||
mat_tri->v[j] = (intptr_t)val[0];
|
||||
mat_tri->l[j] = (intptr_t)l;
|
||||
|
||||
j++;
|
||||
|
||||
|
@ -1664,9 +1777,42 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
|
|||
|
||||
copy_v3_v3(tri->no, f->no);
|
||||
tri->f.i = (intptr_t)f;
|
||||
#endif
|
||||
}
|
||||
TGSET_ITER_END
|
||||
|
||||
TGSET_ITER (f, node->bm_faces) {
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int mat_nr = f->mat_nr;
|
||||
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
|
||||
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
if (l->e->head.hflag & edgeflag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
l->e->head.hflag |= edgeflag;
|
||||
|
||||
int v1 = (int)BLI_ghash_lookup(vmap, (void *)l->e->v1);
|
||||
int v2 = (int)BLI_ghash_lookup(vmap, (void *)l->e->v2);
|
||||
|
||||
pbvh_tribuf_add_edge(node->tribuf, v1, v2);
|
||||
|
||||
v1 = (int)BLI_ghash_lookup(mat_vmaps[mat_nr], (void *)l->e->v1);
|
||||
v2 = (int)BLI_ghash_lookup(mat_vmaps[mat_nr], (void *)l->e->v2);
|
||||
|
||||
pbvh_tribuf_add_edge(mat_tribuf, v1, v2);
|
||||
} while ((l = l->next) != f->l_first);
|
||||
}
|
||||
TGSET_ITER_END
|
||||
|
||||
BLI_array_free(loops);
|
||||
BLI_array_free(loops_idx);
|
||||
|
||||
bm->elem_index_dirty |= BM_VERT;
|
||||
|
||||
node->tri_buffers = tribufs;
|
||||
|
|
|
@ -141,13 +141,22 @@ typedef struct {
|
|||
void *customdata;
|
||||
} BMLogVert;
|
||||
|
||||
#define MAX_FACE_RESERVED 8
|
||||
|
||||
typedef struct {
|
||||
uint v_ids[3];
|
||||
uint l_ids[3];
|
||||
uint *v_ids;
|
||||
uint *l_ids;
|
||||
void **customdata;
|
||||
|
||||
float no[3];
|
||||
void *customdata[3];
|
||||
void *customdata_f;
|
||||
char hflag;
|
||||
|
||||
size_t len;
|
||||
|
||||
void *customdata_res[MAX_FACE_RESERVED];
|
||||
uint v_ids_res[MAX_FACE_RESERVED];
|
||||
uint l_ids_res[MAX_FACE_RESERVED];
|
||||
} BMLogFace;
|
||||
|
||||
/************************* Get/set element IDs ************************/
|
||||
|
@ -328,19 +337,16 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
|
|||
// forcibly copy id
|
||||
// bm_log_copy_id(&bm->pdata, (BMElem *)f, lf->customdata_f);
|
||||
|
||||
BMLoop *l1 = f->l_first;
|
||||
BMLoop *l2 = f->l_first->next;
|
||||
BMLoop *l3 = f->l_first->prev;
|
||||
BMLoop *ls[3] = {l1, l2, l3};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
BMLoop *l = f->l_first;
|
||||
int i = 0;
|
||||
do {
|
||||
if (lf->customdata[i]) {
|
||||
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
|
||||
lf->customdata[i] = NULL;
|
||||
}
|
||||
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
|
||||
}
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, l->head.data, &lf->customdata[i]);
|
||||
} while ((i++, l = l->next) != f->l_first);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -403,28 +409,40 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
|
|||
{
|
||||
BMLogEntry *entry = log->current_entry;
|
||||
BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces);
|
||||
BMVert *v[3];
|
||||
|
||||
lf->customdata_f = lf->customdata[0] = lf->customdata[1] = lf->customdata[2] = NULL;
|
||||
BLI_assert(f->len == 3);
|
||||
lf->len = (size_t)f->len;
|
||||
|
||||
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3);
|
||||
BM_face_as_array_vert_tri(f, v);
|
||||
bool have_loop_ids = (log->bm->idmap.flag & BM_LOOP);
|
||||
|
||||
if (f->len > MAX_FACE_RESERVED) {
|
||||
lf->v_ids = (int *)MEM_callocN(sizeof(*lf->v_ids) * lf->len, "lf->l_ids");
|
||||
lf->l_ids = (int *)MEM_callocN(sizeof(*lf->l_ids) * lf->len, "lf->l_ids");
|
||||
lf->customdata = (void **)MEM_callocN(sizeof(*lf->l_ids) * lf->len, "lf->l_ids");
|
||||
}
|
||||
else {
|
||||
lf->v_ids = lf->v_ids_res;
|
||||
lf->l_ids = lf->l_ids_res;
|
||||
lf->customdata = lf->customdata_res;
|
||||
}
|
||||
|
||||
lf->customdata_f = NULL;
|
||||
|
||||
copy_v3_v3(lf->no, f->no);
|
||||
|
||||
if (log->bm->idmap.flag & BM_LOOP) {
|
||||
lf->l_ids[0] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first);
|
||||
lf->l_ids[1] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first->next);
|
||||
lf->l_ids[2] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first->prev);
|
||||
}
|
||||
else {
|
||||
lf->l_ids[0] = lf->l_ids[1] = lf->l_ids[2] = (uint)-1;
|
||||
}
|
||||
int i = 0;
|
||||
BMLoop *l = f->l_first;
|
||||
do {
|
||||
if (have_loop_ids) {
|
||||
lf->l_ids[i] = (uint)BM_ELEM_GET_ID(log->bm, l);
|
||||
}
|
||||
else {
|
||||
lf->l_ids[i] = (uint)-1;
|
||||
}
|
||||
|
||||
lf->v_ids[0] = bm_log_vert_id_get(log, v[0]);
|
||||
lf->v_ids[1] = bm_log_vert_id_get(log, v[1]);
|
||||
lf->v_ids[2] = bm_log_vert_id_get(log, v[2]);
|
||||
lf->v_ids[i] = bm_log_vert_id_get(log, l->v);
|
||||
|
||||
lf->customdata[i] = NULL;
|
||||
} while ((i++, l = l->next) != f->l_first);
|
||||
|
||||
lf->hflag = f->head.hflag;
|
||||
return lf;
|
||||
|
@ -482,6 +500,9 @@ static void bm_log_faces_unmake(
|
|||
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
|
||||
{
|
||||
GHashIterator gh_iter;
|
||||
BMEdge **e_tri = NULL;
|
||||
BLI_array_staticdeclare(e_tri, 32);
|
||||
|
||||
GHASH_ITER (gh_iter, faces) {
|
||||
void *key = BLI_ghashIterator_getKey(&gh_iter);
|
||||
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
|
||||
|
@ -493,17 +514,23 @@ static void bm_log_faces_unmake(
|
|||
continue;
|
||||
}
|
||||
|
||||
BMEdge *e_tri[3];
|
||||
BMLoop *l_iter;
|
||||
BLI_array_clear(e_tri);
|
||||
|
||||
BMLoop *l;
|
||||
int i;
|
||||
|
||||
l_iter = BM_FACE_FIRST_LOOP(f);
|
||||
for (i = 0; i < 3; i++, l_iter = l_iter->next) {
|
||||
e_tri[i] = l_iter->e;
|
||||
}
|
||||
|
||||
// ensure we have final customdata for face in log
|
||||
#ifdef CUSTOMDATA
|
||||
|
||||
l = f->l_first;
|
||||
i = 0;
|
||||
do {
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, l->head.data, &lf->customdata[i]);
|
||||
}
|
||||
|
||||
BLI_array_append(e_tri, l->e);
|
||||
} while ((i++, l = l->next) != f->l_first);
|
||||
|
||||
if (lf->customdata_f) {
|
||||
CustomData_bmesh_copy_data(&bm->pdata, &entry->pdata, f->head.data, &lf->customdata_f);
|
||||
|
||||
|
@ -511,16 +538,6 @@ static void bm_log_faces_unmake(
|
|||
// bm_log_copy_id(&bm->pdata, (BMElem *)f, lf->customdata_f);
|
||||
}
|
||||
|
||||
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_copy_data(
|
||||
&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (callbacks) {
|
||||
callbacks->on_face_kill(f, callbacks->userdata);
|
||||
}
|
||||
|
@ -528,12 +545,14 @@ static void bm_log_faces_unmake(
|
|||
BM_face_kill(bm, f);
|
||||
|
||||
/* Remove any unused edges */
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (i = 0; i < (int)lf->len; i++) {
|
||||
if (BM_edge_is_wire(e_tri[i])) {
|
||||
BM_edge_kill(bm, e_tri[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_array_free(e_tri);
|
||||
}
|
||||
|
||||
static void bm_log_verts_restore(
|
||||
|
@ -568,35 +587,53 @@ static void bm_log_faces_restore(
|
|||
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
|
||||
{
|
||||
GHashIterator gh_iter;
|
||||
BMVert **vs_tmp = NULL;
|
||||
BLI_array_staticdeclare(vs_tmp, 32);
|
||||
|
||||
bool have_loop_ids = (log->bm->idmap.flag & BM_LOOP);
|
||||
|
||||
GHASH_ITER (gh_iter, faces) {
|
||||
void *key = BLI_ghashIterator_getKey(&gh_iter);
|
||||
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
|
||||
BMVert *v[3] = {
|
||||
bm_log_vert_from_id(log, lf->v_ids[0]),
|
||||
bm_log_vert_from_id(log, lf->v_ids[1]),
|
||||
bm_log_vert_from_id(log, lf->v_ids[2]),
|
||||
};
|
||||
BMFace *f;
|
||||
|
||||
if (!v[0] || !v[1] || !v[2]) {
|
||||
BMIter iter;
|
||||
BMVert *v2;
|
||||
const int cd_id = bm->idmap.cd_id_off[BM_VERT];
|
||||
BLI_array_clear(vs_tmp);
|
||||
bool bad = false;
|
||||
|
||||
BM_ITER_MESH (v2, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
int id = BM_ELEM_CD_GET_INT(v2, cd_id);
|
||||
for (int i = 0; i < (int)lf->len; i++) {
|
||||
BMVert *v = bm_log_vert_from_id(log, lf->v_ids[i]);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!v[i] && lf->v_ids[i] == (uint)id) {
|
||||
printf("found vertex\n");
|
||||
if (!v) {
|
||||
BMIter iter;
|
||||
BMVert *v2;
|
||||
const int cd_id = bm->idmap.cd_id_off[BM_VERT];
|
||||
|
||||
bad = true;
|
||||
|
||||
BM_ITER_MESH (v2, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
int id = BM_ELEM_CD_GET_INT(v2, cd_id);
|
||||
|
||||
if (lf->v_ids[i] == (uint)id) {
|
||||
printf("found vertex %d\n", id);
|
||||
bad = false;
|
||||
v = v2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
printf("Undo error! %p %p %p\n", v[0], v[1], v[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("Undo error! %p %p %p\n", v[0], v[1], v[2]);
|
||||
continue;
|
||||
|
||||
if (bad) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BLI_array_append(vs_tmp, v);
|
||||
}
|
||||
|
||||
f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_SKIP_ID, true);
|
||||
BMFace *f = BM_face_create_verts(bm, vs_tmp, (int)lf->len, NULL, BM_CREATE_SKIP_ID, true);
|
||||
f->head.hflag = lf->hflag;
|
||||
|
||||
copy_v3_v3(f->no, lf->no);
|
||||
|
@ -607,23 +644,25 @@ static void bm_log_faces_restore(
|
|||
|
||||
bm_assign_id(bm, (BMElem *)f, POINTER_AS_UINT(key));
|
||||
|
||||
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
|
||||
BMLoop *l = f->l_first;
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (lf->l_ids[i] != (uint)-1) {
|
||||
bm_assign_id(bm, (BMElem *)ls[i], lf->l_ids[i]);
|
||||
do {
|
||||
if (have_loop_ids) {
|
||||
bm_assign_id(bm, (BMElem *)l, lf->l_ids[j]);
|
||||
}
|
||||
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_copy_data(
|
||||
&entry->ldata, &bm->ldata, lf->customdata[i], &ls[i]->head.data);
|
||||
if (lf->customdata[j]) {
|
||||
CustomData_bmesh_copy_data(&entry->ldata, &bm->ldata, lf->customdata[j], &l->head.data);
|
||||
}
|
||||
}
|
||||
} while ((j++, l = l->next) != f->l_first);
|
||||
|
||||
if (callbacks) {
|
||||
callbacks->on_face_add(f, callbacks->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_array_free(vs_tmp);
|
||||
}
|
||||
|
||||
static void bm_log_vert_values_swap(
|
||||
|
@ -691,7 +730,6 @@ static void bm_log_face_values_swap(BMLog *log,
|
|||
|
||||
void *old_cdata = NULL;
|
||||
|
||||
#ifdef CUSTOMDATA
|
||||
if (f->head.data) {
|
||||
old_cdata = scratch;
|
||||
memcpy(old_cdata, f->head.data, (size_t)log->bm->pdata.totsize);
|
||||
|
@ -701,15 +739,15 @@ static void bm_log_face_values_swap(BMLog *log,
|
|||
CustomData_bmesh_swap_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
|
||||
}
|
||||
|
||||
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
|
||||
int i = 0;
|
||||
BMLoop *l = f->l_first;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
do {
|
||||
if (lf->customdata[i]) {
|
||||
CustomData_bmesh_swap_data(
|
||||
&entry->ldata, &log->bm->ldata, lf->customdata[i], &ls[i]->head.data);
|
||||
&entry->ldata, &log->bm->ldata, lf->customdata[i], &l->head.data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} while ((i++, l = l->next) != f->l_first);
|
||||
|
||||
if (callbacks) {
|
||||
callbacks->on_face_change(f, callbacks->userdata, old_cdata);
|
||||
|
@ -1545,9 +1583,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
|
|||
uint f_id = (uint)BM_ELEM_GET_ID(log->bm, f);
|
||||
void *key = POINTER_FROM_UINT(f_id);
|
||||
|
||||
/* Only triangles are supported for now */
|
||||
BLI_assert(f->len == 3);
|
||||
|
||||
lf = bm_log_face_alloc(log, f);
|
||||
log_ghash_insert(log, log->current_entry->added_faces, key, lf);
|
||||
|
||||
|
|
|
@ -9462,8 +9462,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
|
|||
sd->symmetrize_direction,
|
||||
dist,
|
||||
true);
|
||||
#ifndef DYNTOPO_DYNAMIC_TESS
|
||||
SCULPT_dynamic_topology_triangulate(ss, ss->bm);
|
||||
|
||||
#endif
|
||||
/* Bisect operator flags edges (keep tags clean for edge queue). */
|
||||
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
|
||||
|
||||
|
@ -9600,10 +9601,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
|
|||
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
|
||||
|
||||
const char *message_unsupported = NULL;
|
||||
if (me->totloop != me->totpoly * 3) {
|
||||
message_unsupported = TIP_("non-triangle face");
|
||||
}
|
||||
else if (mmd != NULL) {
|
||||
if (mmd != NULL) {
|
||||
message_unsupported = TIP_("multi-res modifier");
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -508,7 +508,10 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
|
|||
.active_shapekey = ob->shapenr,
|
||||
}));
|
||||
#endif
|
||||
|
||||
#ifndef DYNTOPO_DYNAMIC_TESS
|
||||
SCULPT_dynamic_topology_triangulate(ss, ss->bm);
|
||||
#endif
|
||||
|
||||
SCULPT_dyntopo_node_layers_add(ss);
|
||||
SCULPT_dyntopo_save_origverts(ss);
|
||||
|
|
|
@ -1749,19 +1749,19 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
|
|||
/* 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)
|
||||
ATTR_NO_OPT 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)
|
||||
{
|
||||
|
||||
if (flat_vcol && CustomData_has_layer(&bm->vdata, CD_PROP_COLOR)) {
|
||||
|
@ -1815,7 +1815,15 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
|
|||
return;
|
||||
}
|
||||
|
||||
tottri = gpu_bmesh_face_visible_count(bm_faces, mat_nr);
|
||||
/* 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);
|
||||
|
||||
bool default_face_set = true;
|
||||
|
||||
#ifdef DYNTOPO_DYNAMIC_TESS
|
||||
tottri = tribuf->tottri;
|
||||
totvert = tottri * 3;
|
||||
|
||||
if (!tottri) {
|
||||
|
@ -1827,14 +1835,132 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
|
|||
buffers->tot_tri = 0;
|
||||
return;
|
||||
}
|
||||
/* Fill vertex buffer */
|
||||
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
|
||||
/* Memory map failed */
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
int v_index = 0;
|
||||
|
||||
bool default_face_set = true;
|
||||
GPUIndexBufBuilder elb_lines;
|
||||
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
|
||||
|
||||
for (int i = 0; i < tribuf->tottri; i++) {
|
||||
PBVHTri *tri = tribuf->tris + i;
|
||||
BMFace *f = (BMFace *)tri->f.i;
|
||||
BMLoop **l = (BMLoop **)tri->l;
|
||||
BMVert *v[3];
|
||||
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
v[0] = l[0]->v;
|
||||
v[1] = l[1]->v;
|
||||
v[2] = l[2]->v;
|
||||
|
||||
float fmask = 0.0f;
|
||||
int i;
|
||||
|
||||
/* 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 (tri->eflag & 1) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
|
||||
}
|
||||
|
||||
if (tri->eflag & 2) {
|
||||
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
|
||||
}
|
||||
|
||||
if (tri->eflag & 4) {
|
||||
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 (int j = 0; j < 3; j++) {
|
||||
float *no = buffers->smooth ? v[j]->no : f->no;
|
||||
|
||||
gpu_bmesh_vert_to_buffer_copy(v[j],
|
||||
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 k = 0; k < cd_vcol_count; k++) {
|
||||
MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[j]->v, cd_vcols[k]);
|
||||
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[k], v_index, vcol);
|
||||
}
|
||||
}
|
||||
else if (cd_mcol_offset >= 0) {
|
||||
ushort vcol[4];
|
||||
|
||||
MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l[j], 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[j], 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++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
tottri = tribuf->tottri;
|
||||
totvert = tottri * 3;
|
||||
|
||||
if (!tottri) {
|
||||
/* empty node (i.e. not just hidden)? */
|
||||
if (!BLI_table_gset_len(bm_faces) != 0) {
|
||||
buffers->clear_bmesh_on_flush = true;
|
||||
}
|
||||
|
||||
buffers->tot_tri = 0;
|
||||
return;
|
||||
}
|
||||
/* Fill vertex buffer */
|
||||
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
|
||||
/* Memory map failed */
|
||||
|
@ -1940,6 +2066,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
|
|||
}
|
||||
}
|
||||
TGSET_ITER_END
|
||||
#endif
|
||||
|
||||
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
|
||||
buffers->tot_tri = tottri;
|
||||
|
|
|
@ -547,7 +547,8 @@ enum {
|
|||
DYNVERT_BOUNDARY = (1 << 0),
|
||||
DYNVERT_VERT_FSET_HIDDEN = (1 << 1),
|
||||
DYNVERT_FSET_BOUNDARY = (1 << 2),
|
||||
DYNVERT_NEED_BOUNDARY = (1 << 3)
|
||||
DYNVERT_NEED_BOUNDARY = (1 << 3),
|
||||
DYNVERT_NEED_TRIANGULATE = (1 << 4)
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in New Issue