diff options
Diffstat (limited to 'source')
23 files changed, 4364 insertions, 3536 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 4f68c3fdc7e..1227f4db8e4 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -61,6 +61,26 @@ set(SRC intern/mesh_extractors/extract_mesh_ibo_lines.cc intern/mesh_extractors/extract_mesh_ibo_points.cc intern/mesh_extractors/extract_mesh_ibo_tris.cc + intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc + intern/mesh_extractors/extract_mesh_vbo_edit_data.cc + intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc + intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc + intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc + intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc + intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc + intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc + intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc + intern/mesh_extractors/extract_mesh_vbo_lnor.cc + intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc + intern/mesh_extractors/extract_mesh_vbo_orco.cc + intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc + intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc + intern/mesh_extractors/extract_mesh_vbo_select_idx.cc + intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc + intern/mesh_extractors/extract_mesh_vbo_tan.cc + intern/mesh_extractors/extract_mesh_vbo_uv.cc + intern/mesh_extractors/extract_mesh_vbo_vcol.cc + intern/mesh_extractors/extract_mesh_vbo_weights.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c index 42cd571b089..e813f006351 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c @@ -25,29 +25,10 @@ #include "MEM_guardedalloc.h" -#include "atomic_ops.h" - #include "DNA_object_types.h" -#include "BLI_edgehash.h" -#include "BLI_jitter_2d.h" -#include "BLI_kdopbvh.h" -#include "BLI_string.h" - -#include "BKE_bvhutils.h" -#include "BKE_deform.h" -#include "BKE_editmesh.h" -#include "BKE_editmesh_bvh.h" -#include "BKE_editmesh_cache.h" -#include "BKE_editmesh_tangent.h" -#include "BKE_mesh.h" -#include "BKE_mesh_tangent.h" -#include "BKE_paint.h" - #include "ED_uvedit.h" -#include "GPU_capabilities.h" - #include "draw_cache_extract_mesh_private.h" #include "draw_cache_impl.h" @@ -120,1577 +101,13 @@ const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, /** \} */ /* ---------------------------------------------------------------------- */ -/** \name Extract Position and Vertex Normal - * \{ */ - -typedef struct PosNorLoop { - float pos[3]; - GPUPackedNormal nor; -} PosNorLoop; - -typedef struct MeshExtract_PosNor_Data { - PosNorLoop *vbo_data; - GPUNormal *normals; -} MeshExtract_PosNor_Data; - -static void extract_pos_nor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* WARNING Adjust #PosNorLoop struct accordingly. */ - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_alias_add(&format, "vnor"); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - - /* Pack normals per vert, reduce amount of computation. */ - MeshExtract_PosNor_Data *data = tls_data; - data->vbo_data = (PosNorLoop *)GPU_vertbuf_get_data(vbo); - data->normals = MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__); - - /* Quicker than doing it for each loop. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMVert *eve; - int v; - BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { - data->normals[v].low = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve)); - } - } - else { - const MVert *mv = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mv++) { - data->normals[v].low = GPU_normal_convert_i10_s3(mv->no); - } - } -} - -static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); - vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low; - vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - - PosNorLoop *vert = &data->vbo_data[ml_index]; - const MVert *mv = &mr->mvert[ml->v]; - copy_v3_v3(vert->pos, mv->co); - vert->nor = data->normals[ml->v].low; - /* Flag for paint mode overlay. */ - if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { - vert->nor.w = -1; - } - else if (mv->flag & SELECT) { - vert->nor.w = 1; - } - else { - vert->nor.w = 0; - } - } -} - -static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *eed, - const int ledge_index, - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - - int l_index = mr->loop_len + ledge_index * 2; - PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low; - vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low; -} - -static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *med, - const int ledge_index, - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - const int ml_index = mr->loop_len + ledge_index * 2; - PosNorLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); - vert[0].nor = data->normals[med->v1].low; - vert[1].nor = data->normals[med->v2].low; -} - -static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, - const BMVert *eve, - const int lvert_index, - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - const int l_index = offset + lvert_index; - PosNorLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - vert->nor = data->normals[BM_elem_index_get(eve)].low; -} - -static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, - const MVert *mv, - const int lvert_index, - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - const int ml_index = offset + lvert_index; - const int v_index = mr->lverts[lvert_index]; - PosNorLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert->pos, mv->co); - vert->nor = data->normals[v_index].low; -} - -static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), - void *UNUSED(buf), - void *_data) -{ - MeshExtract_PosNor_Data *data = _data; - MEM_freeN(data->normals); -} - -const MeshExtract extract_pos_nor = { - .init = extract_pos_nor_init, - .iter_poly_bm = extract_pos_nor_iter_poly_bm, - .iter_poly_mesh = extract_pos_nor_iter_poly_mesh, - .iter_ledge_bm = extract_pos_nor_iter_ledge_bm, - .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh, - .iter_lvert_bm = extract_pos_nor_iter_lvert_bm, - .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh, - .finish = extract_pos_nor_finish, - .data_type = 0, - .data_size = sizeof(MeshExtract_PosNor_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Position and High Quality Vertex Normal - * \{ */ - -typedef struct PosNorHQLoop { - float pos[3]; - short nor[4]; -} PosNorHQLoop; - -typedef struct MeshExtract_PosNorHQ_Data { - PosNorHQLoop *vbo_data; - GPUNormal *normals; -} MeshExtract_PosNorHQ_Data; - -static void extract_pos_nor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* WARNING Adjust #PosNorHQLoop struct accordingly. */ - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_alias_add(&format, "vnor"); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - - /* Pack normals per vert, reduce amount of computation. */ - MeshExtract_PosNorHQ_Data *data = tls_data; - data->vbo_data = (PosNorHQLoop *)GPU_vertbuf_get_data(vbo); - data->normals = MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__); - - /* Quicker than doing it for each loop. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMVert *eve; - int v; - BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { - normal_float_to_short_v3(data->normals[v].high, bm_vert_no_get(mr, eve)); - } - } - else { - const MVert *mv = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mv++) { - copy_v3_v3_short(data->normals[v].high, mv->no); - } - } -} - -static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); - copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high); - - BMFace *efa = l_iter->f; - vert->nor[3] = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0; - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - - PosNorHQLoop *vert = &data->vbo_data[ml_index]; - const MVert *mv = &mr->mvert[ml->v]; - copy_v3_v3(vert->pos, mv->co); - copy_v3_v3_short(vert->nor, data->normals[ml->v].high); - - /* Flag for paint mode overlay. */ - if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || - ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && - (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { - vert->nor[3] = -1; - } - else if (mv->flag & SELECT) { - vert->nor[3] = 1; - } - else { - vert->nor[3] = 0; - } - } -} - -static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *eed, - const int ledge_index, - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - int l_index = mr->loop_len + ledge_index * 2; - PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); - copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); - copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high); - vert[0].nor[3] = 0; - copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high); - vert[1].nor[3] = 0; -} - -static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *med, - const int ledge_index, - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - const int ml_index = mr->loop_len + ledge_index * 2; - PosNorHQLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); - copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); - copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high); - vert[0].nor[3] = 0; - copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high); - vert[1].nor[3] = 0; -} - -static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr, - const BMVert *eve, - const int lvert_index, - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - const int l_index = offset + lvert_index; - PosNorHQLoop *vert = &data->vbo_data[l_index]; - copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); - copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high); - vert->nor[3] = 0; -} - -static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr, - const MVert *mv, - const int lvert_index, - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - const int ml_index = offset + lvert_index; - const int v_index = mr->lverts[lvert_index]; - PosNorHQLoop *vert = &data->vbo_data[ml_index]; - copy_v3_v3(vert->pos, mv->co); - copy_v3_v3_short(vert->nor, data->normals[v_index].high); - vert->nor[3] = 0; -} - -static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr), - struct MeshBatchCache *UNUSED(cache), - void *UNUSED(buf), - void *_data) -{ - MeshExtract_PosNorHQ_Data *data = _data; - MEM_freeN(data->normals); -} - -const MeshExtract extract_pos_nor_hq = { - .init = extract_pos_nor_hq_init, - .iter_poly_bm = extract_pos_nor_hq_iter_poly_bm, - .iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh, - .iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm, - .iter_ledge_mesh = extract_pos_nor_hq_iter_ledge_mesh, - .iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm, - .iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh, - .finish = extract_pos_nor_hq_finish, - .data_type = 0, - .data_size = sizeof(MeshExtract_PosNorHQ_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor)}; - -/** \} */ -/* ---------------------------------------------------------------------- */ -/** \name Extract HQ Loop Normal - * \{ */ - -typedef struct gpuHQNor { - short x, y, z, w; -} gpuHQNor; - -static void extract_lnor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_alias_add(&format, "lnor"); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - *(gpuHQNor **)tls_data = GPU_vertbuf_get_data(vbo); -} - -static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - if (mr->loop_normals) { - normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->loop_normals[l_index]); - } - else { - if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { - normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_vert_no_get(mr, l_iter->v)); - } - else { - normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_face_no_get(mr, f)); - } - } - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *data) -{ - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index]; - if (mr->loop_normals) { - normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); - } - else if (mp->flag & ME_SMOOTH) { - copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no); - } - else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]); - } - - /* Flag for paint mode overlay. - * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. - * In paint mode it will use the un-mapped data to draw the wire-frame. */ - if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && - (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mp->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; - } - } -} - -const MeshExtract extract_lnor_hq = { - .init = extract_lnor_hq_init, - .iter_poly_bm = extract_lnor_hq_iter_poly_bm, - .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh, - .data_type = MR_DATA_LOOP_NOR, - .data_size = sizeof(gpuHQNor *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor), -}; - -/** \} */ -/* ---------------------------------------------------------------------- */ -/** \name Extract Loop Normal - * \{ */ - -static void extract_lnor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_alias_add(&format, "lnor"); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - *(GPUPackedNormal **)tls_data = GPU_vertbuf_get_data(vbo); -} - -static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - if (mr->loop_normals) { - (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); - } - else { - if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { - (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3( - bm_vert_no_get(mr, l_iter->v)); - } - else { - (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f)); - } - } - (*(GPUPackedNormal **)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *data) -{ - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index]; - if (mr->loop_normals) { - *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); - } - else if (mp->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no); - } - else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]); - } - - /* Flag for paint mode overlay. - * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. - * In paint mode it will use the un-mapped data to draw the wire-frame. */ - if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && - (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { - lnor_data->w = -1; - } - else if (mp->flag & ME_FACE_SEL) { - lnor_data->w = 1; - } - else { - lnor_data->w = 0; - } - } -} - -const MeshExtract extract_lnor = { - .init = extract_lnor_init, - .iter_poly_bm = extract_lnor_iter_poly_bm, - .iter_poly_mesh = extract_lnor_iter_poly_mesh, - .data_type = MR_DATA_LOOP_NOR, - .data_size = sizeof(GPUPackedNormal *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract UV layers - * \{ */ - -static void extract_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); - - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - uint32_t uv_layers = cache->cd_used.uv; - /* HACK to fix T68857 */ - if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { - int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); - if (layer != -1) { - uv_layers |= (1 << layer); - } - } - - for (int i = 0; i < MAX_MTFACE; i++) { - if (uv_layers & (1 << i)) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); - - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - /* UV layer name. */ - BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - /* Auto layer name. */ - BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); - /* Active render layer name. */ - if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "u"); - } - /* Active display layer name. */ - if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "au"); - /* Alias to `pos` for edit uvs. */ - GPU_vertformat_alias_add(&format, "pos"); - } - /* Stencil mask uv layer name. */ - if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "mu"); - } - } - } - - int v_len = mr->loop_len; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - /* VBO will not be used, only allocate minimum of memory. */ - v_len = 1; - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, v_len); - - float(*uv_data)[2] = (float(*)[2])GPU_vertbuf_get_data(vbo); - for (int i = 0; i < MAX_MTFACE; i++) { - if (uv_layers & (1 << i)) { - if (mr->extract_type == MR_EXTRACT_BMESH) { - int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); - BMIter f_iter; - BMFace *efa; - BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); - memcpy(uv_data, luv->uv, sizeof(*uv_data)); - uv_data++; - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { - memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); - } - } - } - } -} - -const MeshExtract extract_uv = { - .init = extract_uv_init, - .data_type = 0, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Tangent layers - * \{ */ - -static void extract_tan_ex_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - GPUVertBuf *vbo, - const bool do_hq) -{ - GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10; - GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT; - - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); - - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; - uint32_t tan_layers = cache->cd_used.tan; - float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO); - bool orco_allocated = false; - const bool use_orco_tan = cache->cd_used.tan_orco != 0; - - int tan_len = 0; - char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME]; - - for (int i = 0; i < MAX_MTFACE; i++) { - if (tan_layers & (1 << i)) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - /* Tangent layer name. */ - BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode); - /* Active render layer name. */ - if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "t"); - } - /* Active display layer name. */ - if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "at"); - } - - BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME); - } - } - if (use_orco_tan && orco == NULL) { - /* If `orco` is not available compute it ourselves */ - orco_allocated = true; - orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMesh *bm = mr->bm; - for (int v = 0; v < mr->vert_len; v++) { - const BMVert *eve = BM_vert_at_index(bm, v); - /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords. - * not the distorted ones. */ - copy_v3_v3(orco[v], eve->co); - } - } - else { - const MVert *mv = mr->mvert; - for (int v = 0; v < mr->vert_len; v++, mv++) { - copy_v3_v3(orco[v], mv->co); - } - } - BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0); - } - - /* Start Fresh */ - CustomData loop_data; - CustomData_reset(&loop_data); - if (tan_len != 0 || use_orco_tan) { - short tangent_mask = 0; - bool calc_active_tangent = false; - if (mr->extract_type == MR_EXTRACT_BMESH) { - BKE_editmesh_loop_tangent_calc(mr->edit_bmesh, - calc_active_tangent, - tangent_names, - tan_len, - mr->poly_normals, - mr->loop_normals, - orco, - &loop_data, - mr->loop_len, - &tangent_mask); - } - else { - BKE_mesh_calc_loop_tangent_ex(mr->mvert, - mr->mpoly, - mr->poly_len, - mr->mloop, - mr->mlooptri, - mr->tri_len, - cd_ldata, - calc_active_tangent, - tangent_names, - tan_len, - mr->poly_normals, - mr->loop_normals, - orco, - &loop_data, - mr->loop_len, - &tangent_mask); - } - } - - if (use_orco_tan) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(&loop_data, CD_TANGENT, 0); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode); - GPU_vertformat_alias_add(&format, "t"); - GPU_vertformat_alias_add(&format, "at"); - } - - if (orco_allocated) { - MEM_SAFE_FREE(orco); - } - - int v_len = mr->loop_len; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - /* VBO will not be used, only allocate minimum of memory. */ - v_len = 1; - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, v_len); - - if (do_hq) { - short(*tan_data)[4] = (short(*)[4])GPU_vertbuf_get_data(vbo); - for (int i = 0; i < tan_len; i++) { - const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( - &loop_data, CD_TANGENT, name); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { - normal_float_to_short_v3(*tan_data, layer_data[ml_index]); - (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; - tan_data++; - } - } - if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { - normal_float_to_short_v3(*tan_data, layer_data[ml_index]); - (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; - tan_data++; - } - } - } - else { - GPUPackedNormal *tan_data = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo); - for (int i = 0; i < tan_len; i++) { - const char *name = tangent_names[i]; - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( - &loop_data, CD_TANGENT, name); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); - tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; - tan_data++; - } - } - if (use_orco_tan) { - float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { - *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); - tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; - tan_data++; - } - } - } - - CustomData_free(&loop_data, mr->loop_len); -} - -static void extract_tan_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) -{ - extract_tan_ex_init(mr, cache, buf, false); -} - -const MeshExtract extract_tan = { - .init = extract_tan_init, - .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract HQ Tangent layers - * \{ */ - -static void extract_tan_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) -{ - extract_tan_ex_init(mr, cache, buf, true); -} - -const MeshExtract extract_tan_hq = { - .init = extract_tan_hq_init, - .data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Sculpt Data +/** \name Extract Edit Flag Utils * \{ */ -static void extract_sculpt_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - GPUVertFormat format = {0}; - - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; - CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata; - - float *cd_mask = CustomData_get_layer(cd_vdata, CD_PAINT_MASK); - int *cd_face_set = CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); - - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - typedef struct gpuSculptData { - uint8_t face_set_color[4]; - float mask; - } gpuSculptData; - - gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo); - MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK); - int cd_face_set_ofs = CustomData_get_offset(cd_pdata, CD_SCULPT_FACE_SETS); - BMIter f_iter; - BMFace *efa; - BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - float v_mask = 0.0f; - if (cd_mask) { - v_mask = BM_ELEM_CD_GET_FLOAT(l_iter->v, cd_mask_ofs); - } - vbo_data->mask = v_mask; - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - if (cd_face_set) { - const int face_set_id = BM_ELEM_CD_GET_INT(l_iter->f, cd_face_set_ofs); - if (face_set_id != mr->me->face_sets_color_default) { - BKE_paint_face_set_overlay_color_get( - face_set_id, mr->me->face_sets_color_seed, face_set_color); - } - } - copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color); - vbo_data++; - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - int mp_loop = 0; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { - const MPoly *p = &mr->mpoly[mp_index]; - for (int l = 0; l < p->totloop; l++) { - float v_mask = 0.0f; - if (cd_mask) { - v_mask = cd_mask[loops[mp_loop].v]; - } - vbo_data->mask = v_mask; - - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - if (cd_face_set) { - const int face_set_id = cd_face_set[mp_index]; - /* Skip for the default color Face Set to render it white. */ - if (face_set_id != mr->me->face_sets_color_default) { - BKE_paint_face_set_overlay_color_get( - face_set_id, mr->me->face_sets_color_seed, face_set_color); - } - } - copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color); - mp_loop++; - vbo_data++; - } - } - } -} - -const MeshExtract extract_sculpt_data = { - .init = extract_sculpt_data_init, - .data_type = 0, - .data_size = 0, - /* TODO: enable threading. */ - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract VCol - * \{ */ - -static void extract_vcol_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); - - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; - uint32_t vcol_layers = cache->cd_used.vcol; - uint32_t svcol_layers = cache->cd_used.sculpt_vcol; - - for (int i = 0; i < MAX_MCOL; i++) { - if (vcol_layers & (1 << i)) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - - BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - - if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "c"); - } - if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "ac"); - } - - /* Gather number of auto layers. */ - /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 && - CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) { - BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); - } - } - } - - /* Sculpt Vertex Colors */ - if (U.experimental.use_sculpt_vertex_colors) { - for (int i = 0; i < 8; i++) { - if (svcol_layers & (1 << i)) { - char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; - const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i); - GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); - - BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - - if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { - GPU_vertformat_alias_add(&format, "c"); - } - if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { - GPU_vertformat_alias_add(&format, "ac"); - } - /* Gather number of auto layers. */ - /* We only do `vcols` that are not overridden by `uvs`. */ - if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { - BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); - } - } - } - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - typedef struct gpuMeshVcol { - ushort r, g, b, a; - } gpuMeshVcol; - - gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); - MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP); - - for (int i = 0; i < MAX_MCOL; i++) { - if (vcol_layers & (1 << i)) { - if (mr->extract_type == MR_EXTRACT_BMESH) { - int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); - BMIter f_iter; - BMFace *efa; - BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); - vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); - vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); - vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); - vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); - vcol_data++; - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) { - vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); - vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); - vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); - vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); - } - } - } - - if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) { - if (mr->extract_type == MR_EXTRACT_BMESH) { - int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); - BMIter f_iter; - BMFace *efa; - BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); - vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]); - vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]); - vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]); - vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]); - vcol_data++; - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); - for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) { - vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]); - vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]); - vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]); - vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]); - } - } - } - } -} - -const MeshExtract extract_vcol = { - .init = extract_vcol_init, - .data_type = 0, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Orco - * \{ */ - -typedef struct MeshExtract_Orco_Data { - float (*vbo_data)[4]; - float (*orco)[3]; -} MeshExtract_Orco_Data; - -static void extract_orco_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex - * attributes. This is a substantial waste of video-ram and should be done another way. - * Unfortunately, at the time of writing, I did not found any other "non disruptive" - * alternative. */ - GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - CustomData *cd_vdata = &mr->me->vdata; - - MeshExtract_Orco_Data *data = tls_data; - data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo); - data->orco = CustomData_get_layer(cd_vdata, CD_ORCO); - /* Make sure `orco` layer was requested only if needed! */ - BLI_assert(data->orco); -} - -static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int UNUSED(f_index), - void *data) -{ - MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - float *loop_orco = orco_data->vbo_data[l_index]; - copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(l_iter->v)]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *data) -{ - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; - float *loop_orco = orco_data->vbo_data[ml_index]; - copy_v3_v3(loop_orco, orco_data->orco[ml->v]); - loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ - } -} - -const MeshExtract extract_orco = { - .init = extract_orco_init, - .iter_poly_bm = extract_orco_iter_poly_bm, - .iter_poly_mesh = extract_orco_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_Orco_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edge Factor - * Defines how much an edge is visible. - * \{ */ - -typedef struct MeshExtract_EdgeFac_Data { - uchar *vbo_data; - bool use_edge_render; - /* Number of loop per edge. */ - uchar *edge_loop_count; -} MeshExtract_EdgeFac_Data; - -static float loop_edge_factor_get(const float f_no[3], - const float v_co[3], - const float v_no[3], - const float v_next_co[3]) -{ - float enor[3], evec[3]; - sub_v3_v3v3(evec, v_next_co, v_co); - cross_v3_v3v3(enor, v_no, evec); - normalize_v3(enor); - float d = fabsf(dot_v3v3(enor, f_no)); - /* Re-scale to the slider range. */ - d *= (1.0f / 0.065f); - CLAMP(d, 0.0f, 1.0f); - return d; -} - -static void extract_edge_fac_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - - MeshExtract_EdgeFac_Data *data = tls_data; - - if (mr->extract_type == MR_EXTRACT_MESH) { - data->edge_loop_count = MEM_callocN(sizeof(uint32_t) * mr->edge_len, __func__); - - /* HACK(fclem) Detecting the need for edge render. - * We could have a flag in the mesh instead or check the modifier stack. */ - const MEdge *med = mr->medge; - for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { - if ((med->flag & ME_EDGERENDER) == 0) { - data->use_edge_render = true; - break; - } - } - } - else { - /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */ - data->use_edge_render = true; - } - - data->vbo_data = GPU_vertbuf_get_data(vbo); -} - -static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_EdgeFac_Data *data = _data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - - if (BM_edge_is_manifold(l_iter->e)) { - float ratio = loop_edge_factor_get(bm_face_no_get(mr, f), - bm_vert_co_get(mr, l_iter->v), - bm_vert_no_get(mr, l_iter->v), - bm_vert_co_get(mr, l_iter->next->v)); - data->vbo_data[l_index] = ratio * 253 + 1; - } - else { - data->vbo_data[l_index] = 255; - } - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *_data) -{ - MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data; - - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - - if (data->use_edge_render) { - const MEdge *med = &mr->medge[ml->e]; - data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; - } - else { - - /* Count loop per edge to detect non-manifold. */ - if (data->edge_loop_count[ml->e] < 3) { - data->edge_loop_count[ml->e]++; - } - if (data->edge_loop_count[ml->e] == 2) { - /* Manifold */ - const int ml_index_last = mp->totloop + mp->loopstart - 1; - const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); - const MLoop *ml_next = &mr->mloop[ml_index_other]; - const MVert *v1 = &mr->mvert[ml->v]; - const MVert *v2 = &mr->mvert[ml_next->v]; - float vnor_f[3]; - normal_short_to_float_v3(vnor_f, v1->no); - float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co); - data->vbo_data[ml_index] = ratio * 253 + 1; - } - else { - /* Non-manifold */ - data->vbo_data[ml_index] = 255; - } - } - } -} - -static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *UNUSED(eed), - const int ledge_index, - void *_data) -{ - MeshExtract_EdgeFac_Data *data = _data; - data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; - data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; -} - -static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *UNUSED(med), - const int ledge_index, - void *_data) -{ - MeshExtract_EdgeFac_Data *data = _data; - - data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; - data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; -} - -static void extract_edge_fac_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *_data) -{ - GPUVertBuf *vbo = buf; - MeshExtract_EdgeFac_Data *data = _data; - - if (GPU_crappy_amd_driver()) { - /* Some AMD drivers strangely crash with VBO's with a one byte format. - * To workaround we reinitialize the VBO with another format and convert - * all bytes to floats. */ - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - /* We keep the data reference in data->vbo_data. */ - data->vbo_data = GPU_vertbuf_steal_data(vbo); - GPU_vertbuf_clear(vbo); - - int buf_len = mr->loop_len + mr->loop_loose_len; - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, buf_len); - - float *fdata = (float *)GPU_vertbuf_get_data(vbo); - for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) { - *fdata = data->vbo_data[ml_index] / 255.0f; - } - /* Free old byte data. */ - MEM_freeN(data->vbo_data); - } - MEM_SAFE_FREE(data->edge_loop_count); -} - -const MeshExtract extract_edge_fac = { - .init = extract_edge_fac_init, - .iter_poly_bm = extract_edge_fac_iter_poly_bm, - .iter_poly_mesh = extract_edge_fac_iter_poly_mesh, - .iter_ledge_bm = extract_edge_fac_iter_ledge_bm, - .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh, - .finish = extract_edge_fac_finish, - .data_type = MR_DATA_POLY_NOR, - .data_size = sizeof(MeshExtract_EdgeFac_Data), - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac)}; - -/** \} */ -/* ---------------------------------------------------------------------- */ -/** \name Extract Vertex Weight - * \{ */ - -typedef struct MeshExtract_Weight_Data { - float *vbo_data; - const DRW_MeshWeightState *wstate; - const MDeformVert *dvert; /* For #Mesh. */ - int cd_ofs; /* For #BMesh. */ -} MeshExtract_Weight_Data; - -static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) -{ - /* Error state. */ - if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) { - return -2.0f; - } - if (dvert == NULL) { - return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f; - } - - float input = 0.0f; - if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) { - /* Multi-Paint feature */ - bool is_normalized = (wstate->flags & (DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE | - DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE)); - input = BKE_defvert_multipaint_collective_weight(dvert, - wstate->defgroup_len, - wstate->defgroup_sel, - wstate->defgroup_sel_count, - is_normalized); - /* make it black if the selected groups have no weight on a vertex */ - if (input == 0.0f) { - return -1.0f; - } - } - else { - /* default, non tricky behavior */ - input = BKE_defvert_find_weight(dvert, wstate->defgroup_active); - - if (input == 0.0f) { - switch (wstate->alert_mode) { - case OB_DRAW_GROUPUSER_ACTIVE: - return -1.0f; - break; - case OB_DRAW_GROUPUSER_ALL: - if (BKE_defvert_is_weight_zero(dvert, wstate->defgroup_len)) { - return -1.0f; - } - break; - } - } - } - - /* Lock-Relative: display the fraction of current weight vs total unlocked weight. */ - if (wstate->flags & DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE) { - input = BKE_defvert_lock_relative_weight( - input, dvert, wstate->defgroup_len, wstate->defgroup_locked, wstate->defgroup_unlocked); - } - - CLAMP(input, 0.0f, 1.0f); - return input; -} - -static void extract_weights_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - - MeshExtract_Weight_Data *data = tls_data; - data->vbo_data = (float *)GPU_vertbuf_get_data(vbo); - data->wstate = &cache->weight_state; - - if (data->wstate->defgroup_active == -1) { - /* Nothing to show. */ - data->dvert = NULL; - data->cd_ofs = -1; - } - else if (mr->extract_type == MR_EXTRACT_BMESH) { - data->dvert = NULL; - data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT); - } - else { - data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT); - data->cd_ofs = -1; - } -} - -static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_Weight_Data *data = _data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - if (data->cd_ofs != -1) { - const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l_iter->v, data->cd_ofs); - data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); - } - else { - data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate); - } - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *_data) -{ - MeshExtract_Weight_Data *data = _data; - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - if (data->dvert != NULL) { - const MDeformVert *dvert = &data->dvert[ml->v]; - data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); - } - else { - const MDeformVert *dvert = NULL; - data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); - } - } -} - -const MeshExtract extract_weights = { - .init = extract_weights_init, - .iter_poly_bm = extract_weights_iter_poly_bm, - .iter_poly_mesh = extract_weights_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_Weight_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights), -}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit Mode Data / Flags - * \{ */ - -typedef struct EditLoopData { - uchar v_flag; - uchar e_flag; - uchar crease; - uchar bweight; -} EditLoopData; - -static void mesh_render_data_face_flag(const MeshRenderData *mr, - const BMFace *efa, - const int cd_ofs, - EditLoopData *eattr) +void mesh_render_data_face_flag(const MeshRenderData *mr, + const BMFace *efa, + const int cd_ofs, + EditLoopData *eattr) { if (efa == mr->efa_act) { eattr->v_flag |= VFLAG_FACE_ACTIVE; @@ -1708,7 +125,8 @@ static void mesh_render_data_face_flag(const MeshRenderData *mr, #ifdef WITH_FREESTYLE if (mr->freestyle_face_ofs != -1) { - const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, mr->freestyle_face_ofs); + const FreestyleFace *ffa = (const FreestyleFace *)BM_ELEM_CD_GET_VOID_P( + efa, mr->freestyle_face_ofs); if (ffa->flag & FREESTYLE_FACE_MARK) { eattr->v_flag |= VFLAG_FACE_FREESTYLE; } @@ -1716,78 +134,15 @@ static void mesh_render_data_face_flag(const MeshRenderData *mr, #endif } -static void mesh_render_data_edge_flag(const MeshRenderData *mr, - const BMEdge *eed, - EditLoopData *eattr) -{ - const ToolSettings *ts = mr->toolsettings; - const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0; - const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE); - - if (eed == mr->eed_act) { - eattr->e_flag |= VFLAG_EDGE_ACTIVE; - } - if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - eattr->e_flag |= VFLAG_EDGE_SELECTED; - } - if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) { - eattr->e_flag |= VFLAG_EDGE_SELECTED; - eattr->e_flag |= VFLAG_VERT_SELECTED; - } - if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) { - eattr->e_flag |= VFLAG_EDGE_SEAM; - } - if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) { - eattr->e_flag |= VFLAG_EDGE_SHARP; - } - - /* Use active edge color for active face edges because - * specular highlights make it hard to see T55456#510873. - * - * This isn't ideal since it can't be used when mixing edge/face modes - * but it's still better than not being able to see the active face. */ - if (is_face_only_select_mode) { - if (mr->efa_act != NULL) { - if (BM_edge_in_face(eed, mr->efa_act)) { - eattr->e_flag |= VFLAG_EDGE_ACTIVE; - } - } - } - - /* Use a byte for value range */ - if (mr->crease_ofs != -1) { - float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs); - if (crease > 0) { - eattr->crease = (uchar)(crease * 255.0f); - } - } - /* Use a byte for value range */ - if (mr->bweight_ofs != -1) { - float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs); - if (bweight > 0) { - eattr->bweight = (uchar)(bweight * 255.0f); - } - } -#ifdef WITH_FREESTYLE - if (mr->freestyle_edge_ofs != -1) { - const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, mr->freestyle_edge_ofs); - if (fed->flag & FREESTYLE_EDGE_MARK) { - eattr->e_flag |= VFLAG_EDGE_FREESTYLE; - } - } -#endif -} - -static void mesh_render_data_loop_flag(const MeshRenderData *mr, - BMLoop *l, - const int cd_ofs, - EditLoopData *eattr) +void mesh_render_data_loop_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr) { if (cd_ofs == -1) { return; } - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs); + MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs); if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) { eattr->v_flag |= VFLAG_VERT_UV_PINNED; } @@ -1796,10 +151,10 @@ static void mesh_render_data_loop_flag(const MeshRenderData *mr, } } -static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, - BMLoop *l, - const int cd_ofs, - EditLoopData *eattr) +void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr) { if (cd_ofs == -1) { return; @@ -1810,1879 +165,4 @@ static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, } } -static void mesh_render_data_vert_flag(const MeshRenderData *mr, - const BMVert *eve, - EditLoopData *eattr) -{ - if (eve == mr->eve_act) { - eattr->e_flag |= VFLAG_VERT_ACTIVE; - } - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - eattr->e_flag |= VFLAG_VERT_SELECTED; - } -} - -static void extract_edit_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* WARNING: Adjust #EditLoopData struct accordingly. */ - GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); - GPU_vertformat_alias_add(&format, "flag"); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - EditLoopData *vbo_data = GPU_vertbuf_get_data(vbo); - *(EditLoopData **)tls_data = vbo_data; -} - -static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - - EditLoopData *data = vbo_data + l_index; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_face_flag(mr, f, -1, data); - mesh_render_data_edge_flag(mr, l_iter->e, data); - mesh_render_data_vert_flag(mr, l_iter->v, data); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - EditLoopData *data = vbo_data + ml_index; - memset(data, 0x0, sizeof(*data)); - BMFace *efa = bm_original_face_get(mr, mp_index); - BMEdge *eed = bm_original_edge_get(mr, ml->e); - BMVert *eve = bm_original_vert_get(mr, ml->v); - if (efa) { - mesh_render_data_face_flag(mr, efa, -1, data); - } - if (eed) { - mesh_render_data_edge_flag(mr, eed, data); - } - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); - } - } -} - -static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *eed, - const int ledge_index, - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - EditLoopData *data = vbo_data + mr->loop_len + (ledge_index * 2); - memset(data, 0x0, sizeof(*data) * 2); - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - mesh_render_data_vert_flag(mr, eed->v1, &data[0]); - mesh_render_data_vert_flag(mr, eed->v2, &data[1]); -} - -static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *med, - const int ledge_index, - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - EditLoopData *data = vbo_data + mr->loop_len + ledge_index * 2; - memset(data, 0x0, sizeof(*data) * 2); - const int e_index = mr->ledges[ledge_index]; - BMEdge *eed = bm_original_edge_get(mr, e_index); - BMVert *eve1 = bm_original_vert_get(mr, med->v1); - BMVert *eve2 = bm_original_vert_get(mr, med->v2); - if (eed) { - mesh_render_data_edge_flag(mr, eed, &data[0]); - data[1] = data[0]; - } - if (eve1) { - mesh_render_data_vert_flag(mr, eve1, &data[0]); - } - if (eve2) { - mesh_render_data_vert_flag(mr, eve2, &data[1]); - } -} - -static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, - const BMVert *eve, - const int lvert_index, - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - EditLoopData *data = vbo_data + offset + lvert_index; - memset(data, 0x0, sizeof(*data)); - mesh_render_data_vert_flag(mr, eve, data); -} - -static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, - const MVert *UNUSED(mv), - const int lvert_index, - void *_data) -{ - EditLoopData *vbo_data = *(EditLoopData **)_data; - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - EditLoopData *data = vbo_data + offset + lvert_index; - memset(data, 0x0, sizeof(*data)); - const int v_index = mr->lverts[lvert_index]; - BMVert *eve = bm_original_vert_get(mr, v_index); - if (eve) { - mesh_render_data_vert_flag(mr, eve, data); - } -} - -const MeshExtract extract_edit_data = { - .init = extract_edit_data_init, - .iter_poly_bm = extract_edit_data_iter_poly_bm, - .iter_poly_mesh = extract_edit_data_iter_poly_mesh, - .iter_ledge_bm = extract_edit_data_iter_ledge_bm, - .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh, - .iter_lvert_bm = extract_edit_data_iter_lvert_bm, - .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh, - .data_type = 0, - .data_size = sizeof(EditLoopData *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data)}; - /** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit UV Data / Flags - * \{ */ - -typedef struct MeshExtract_EditUVData_Data { - EditLoopData *vbo_data; - int cd_ofs; -} MeshExtract_EditUVData_Data; - -static void extract_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* WARNING: Adjust #EditLoopData struct accordingly. */ - GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); - GPU_vertformat_alias_add(&format, "flag"); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - - MeshExtract_EditUVData_Data *data = tls_data; - data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); - data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); -} - -static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - MeshExtract_EditUVData_Data *data = _data; - EditLoopData *eldata = &data->vbo_data[l_index]; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_loop_flag(mr, l_iter, data->cd_ofs, eldata); - mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, l_iter, data->cd_ofs, eldata); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *_data) -{ - MeshExtract_EditUVData_Data *data = _data; - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - - EditLoopData *eldata = &data->vbo_data[ml_index]; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, mp_index); - if (efa) { - BMEdge *eed = bm_original_edge_get(mr, ml->e); - BMVert *eve = bm_original_vert_get(mr, ml->v); - if (eed && eve) { - /* Loop on an edge endpoint. */ - BMLoop *l = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); - mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); - } - else { - if (eed == NULL) { - /* Find if the loop's vert is not part of an edit edge. - * For this, we check if the previous loop was on an edge. */ - const int ml_index_last = mp->loopstart + mp->totloop - 1; - const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1); - const MLoop *ml_prev = &mr->mloop[l_prev]; - eed = bm_original_edge_get(mr, ml_prev->e); - } - if (eed) { - /* Mapped points on an edge between two edit verts. */ - BMLoop *l = BM_face_edge_share_loop(efa, eed); - mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); - } - } - } - } -} - -const MeshExtract extract_edituv_data = { - .init = extract_edituv_data_init, - .iter_poly_bm = extract_edituv_data_iter_poly_bm, - .iter_poly_mesh = extract_edituv_data_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_EditUVData_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit UV area stretch - * \{ */ - -static void extract_edituv_stretch_area_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); -} - -BLI_INLINE float area_ratio_get(float area, float uvarea) -{ - if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) { - /* Tag inversion by using the sign. */ - return (area > uvarea) ? (uvarea / area) : -(area / uvarea); - } - return 0.0f; -} - -BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) -{ - ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; - return (ratio > 1.0f) ? (1.0f / ratio) : ratio; -} - -static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(data)) -{ - GPUVertBuf *vbo = buf; - float tot_area = 0.0f, tot_uv_area = 0.0f; - float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - CustomData *cd_ldata = &mr->bm->ldata; - int uv_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); - - BMFace *efa; - BMIter f_iter; - int f; - BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { - float area = BM_face_calc_area(efa); - float uvarea = BM_face_calc_area_uv(efa, uv_ofs); - tot_area += area; - tot_uv_area += uvarea; - area_ratio[f] = area_ratio_get(area, uvarea); - } - } - else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); - const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - const MPoly *mp = mr->mpoly; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert); - float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); - tot_area += area; - tot_uv_area += uvarea; - area_ratio[mp_index] = area_ratio_get(area, uvarea); - } - } - - cache->tot_area = tot_area; - cache->tot_uv_area = tot_uv_area; - - /* Convert in place to avoid an extra allocation */ - uint16_t *poly_stretch = (uint16_t *)area_ratio; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { - poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; - } - - /* Copy face data for each loop. */ - uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMFace *efa; - BMIter f_iter; - int f, l_index = 0; - BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { - for (int i = 0; i < efa->len; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[f]; - } - } - } - else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); - const MPoly *mp = mr->mpoly; - for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - for (int i = 0; i < mp->totloop; i++, l_index++) { - loop_stretch[l_index] = poly_stretch[mp_index]; - } - } - } - - MEM_freeN(area_ratio); -} - -const MeshExtract extract_edituv_stretch_area = { - .init = extract_edituv_stretch_area_init, - .finish = extract_edituv_stretch_area_finish, - .data_type = 0, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit UV angle stretch - * \{ */ - -typedef struct UVStretchAngle { - int16_t angle; - int16_t uv_angles[2]; -} UVStretchAngle; - -typedef struct MeshExtract_StretchAngle_Data { - UVStretchAngle *vbo_data; - MLoopUV *luv; - float auv[2][2], last_auv[2]; - float av[2][3], last_av[3]; - int cd_ofs; -} MeshExtract_StretchAngle_Data; - -static void compute_normalize_edge_vectors(float auv[2][2], - float av[2][3], - const float uv[2], - const float uv_prev[2], - const float co[3], - const float co_prev[3]) -{ - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* 2d edge */ - sub_v2_v2v2(auv[1], uv_prev, uv); - normalize_v2(auv[1]); - /* 3d edge */ - sub_v3_v3v3(av[1], co_prev, co); - normalize_v3(av[1]); -} - -static short v2_to_short_angle(const float v[2]) -{ - return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX; -} - -static void edituv_get_edituv_stretch_angle(float auv[2][2], - const float av[2][3], - UVStretchAngle *r_stretch) -{ - /* Send UV's to the shader and let it compute the aspect corrected angle. */ - r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]); - r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]); - /* Compute 3D angle here. */ - r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX; - -#if 0 /* here for reference, this is done in shader now. */ - float uvang = angle_normalized_v2v2(auv0, auv1); - float ang = angle_normalized_v3v3(av0, av1); - float stretch = fabsf(uvang - ang) / (float)M_PI; - return 1.0f - pow2f(1.0f - stretch); -#endif -} - -static void extract_edituv_stretch_angle_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* Waning: adjust #UVStretchAngle struct accordingly. */ - GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); - - MeshExtract_StretchAngle_Data *data = tls_data; - data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo); - - /* Special iterator needed to save about half of the computing cost. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); - } - else { - BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); - data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - } -} - -static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_StretchAngle_Data *data = _data; - float(*auv)[2] = data->auv, *last_auv = data->last_auv; - float(*av)[3] = data->av, *last_av = data->last_av; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - - const MLoopUV *luv, *luv_next; - BMLoop *l_next = l_iter->next; - if (l_iter == BM_FACE_FIRST_LOOP(f)) { - /* First loop in face. */ - BMLoop *l_tmp = l_iter->prev; - BMLoop *l_next_tmp = l_iter; - luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, l_tmp->v), - bm_vert_co_get(mr, l_next_tmp->v)); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == BM_FACE_FIRST_LOOP(f)) { - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); - } - else { - luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); - luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); - compute_normalize_edge_vectors(auv, - av, - luv->uv, - luv_next->uv, - bm_vert_co_get(mr, l_iter->v), - bm_vert_co_get(mr, l_next->v)); - } - edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *_data) -{ - MeshExtract_StretchAngle_Data *data = _data; - - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - float(*auv)[2] = data->auv, *last_auv = data->last_auv; - float(*av)[3] = data->av, *last_av = data->last_av; - int l_next = ml_index + 1; - const MVert *v, *v_next; - if (ml_index == mp->loopstart) { - /* First loop in face. */ - const int ml_index_last = ml_index_end - 1; - const int l_next_tmp = mp->loopstart; - v = &mr->mvert[mr->mloop[ml_index_last].v]; - v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); - /* Save last edge. */ - copy_v2_v2(last_auv, auv[1]); - copy_v3_v3(last_av, av[1]); - } - if (l_next == ml_index_end) { - l_next = mp->loopstart; - /* Move previous edge. */ - copy_v2_v2(auv[0], auv[1]); - copy_v3_v3(av[0], av[1]); - /* Copy already calculated last edge. */ - copy_v2_v2(auv[1], last_auv); - copy_v3_v3(av[1], last_av); - } - else { - v = &mr->mvert[mr->mloop[ml_index].v]; - v_next = &mr->mvert[mr->mloop[l_next].v]; - compute_normalize_edge_vectors( - auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co); - } - edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]); - } -} - -const MeshExtract extract_edituv_stretch_angle = { - .init = extract_edituv_stretch_angle_init, - .iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm, - .iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_StretchAngle_Data), - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Edit Mesh Analysis Colors - * \{ */ - -static void extract_mesh_analysis_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); -} - -static void axis_from_enum_v3(float v[3], const char axis) -{ - zero_v3(v); - if (axis < 3) { - v[axis] = 1.0f; - } - else { - v[axis - 3] = -1.0f; - } -} - -BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange) -{ - if (fac < min) { - fac = 1.0f; - } - else if (fac > max) { - fac = -1.0f; - } - else { - fac = (fac - min) * minmax_irange; - fac = 1.0f - fac; - CLAMP(fac, 0.0f, 1.0f); - } - return fac; -} - -static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) -{ - const MeshStatVis *statvis = &mr->toolsettings->statvis; - const float min = statvis->overhang_min / (float)M_PI; - const float max = statvis->overhang_max / (float)M_PI; - const char axis = statvis->overhang_axis; - BMEditMesh *em = mr->edit_bmesh; - BMIter iter; - BMesh *bm = em->bm; - BMFace *f; - float dir[3]; - const float minmax_irange = 1.0f / (max - min); - - BLI_assert(min <= max); - - axis_from_enum_v3(dir, axis); - - /* now convert into global space */ - mul_transposed_mat3_m4_v3(mr->obmat, dir); - normalize_v3(dir); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - int l_index = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; - fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l_index++) { - r_overhang[l_index] = fac; - } - } - } - else { - const MPoly *mp = mr->mpoly; - for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI; - fac = overhang_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mp->totloop; i++, l_index++) { - r_overhang[l_index] = fac; - } - } - } -} - -/** - * Needed so we can use jitter values for face interpolation. - */ -static void uv_from_jitter_v2(float uv[2]) -{ - uv[0] += 0.5f; - uv[1] += 0.5f; - if (uv[0] + uv[1] > 1.0f) { - uv[0] = 1.0f - uv[0]; - uv[1] = 1.0f - uv[1]; - } - - clamp_v2(uv, 0.0f, 1.0f); -} - -BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange) -{ - /* important not '<=' */ - if (fac < max) { - fac = (fac - min) * minmax_irange; - fac = 1.0f - fac; - CLAMP(fac, 0.0f, 1.0f); - } - else { - fac = -1.0f; - } - return fac; -} - -static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) -{ - const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */ - /* cheating to avoid another allocation */ - float *face_dists = r_thickness + (mr->loop_len - mr->poly_len); - BMEditMesh *em = mr->edit_bmesh; - const float scale = 1.0f / mat4_to_scale(mr->obmat); - const MeshStatVis *statvis = &mr->toolsettings->statvis; - const float min = statvis->thickness_min * scale; - const float max = statvis->thickness_max * scale; - const float minmax_irange = 1.0f / (max - min); - const int samples = statvis->thickness_samples; - float jit_ofs[32][2]; - BLI_assert(samples <= 32); - BLI_assert(min <= max); - - copy_vn_fl(face_dists, mr->poly_len, max); - - BLI_jitter_init(jit_ofs, samples); - for (int j = 0; j < samples; j++) { - uv_from_jitter_v2(jit_ofs[j]); - } - - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMesh *bm = em->bm; - BM_mesh_elem_index_ensure(bm, BM_FACE); - - struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false); - struct BMLoop *(*looptris)[3] = em->looptris; - for (int i = 0; i < mr->tri_len; i++) { - BMLoop **ltri = looptris[i]; - const int index = BM_elem_index_get(ltri[0]->f); - const float *cos[3] = { - bm_vert_co_get(mr, ltri[0]->v), - bm_vert_co_get(mr, ltri[1]->v), - bm_vert_co_get(mr, ltri[2]->v), - }; - float ray_co[3]; - float ray_no[3]; - - normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); - - for (int j = 0; j < samples; j++) { - float dist = face_dists[index]; - interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]); - madd_v3_v3fl(ray_co, ray_no, eps_offset); - - BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL); - if (f_hit && dist < face_dists[index]) { - float angle_fac = fabsf( - dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit))); - angle_fac = 1.0f - angle_fac; - angle_fac = angle_fac * angle_fac * angle_fac; - angle_fac = 1.0f - angle_fac; - dist /= angle_fac; - if (dist < face_dists[index]) { - face_dists[index] = dist; - } - } - } - } - BKE_bmbvh_free(bmtree); - - BMIter iter; - BMFace *f; - int l_index = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - float fac = face_dists[BM_elem_index_get(f)]; - fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l_index++) { - r_thickness[l_index] = fac; - } - } - } - else { - BVHTreeFromMesh treeData = {NULL}; - - BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4); - const MLoopTri *mlooptri = mr->mlooptri; - for (int i = 0; i < mr->tri_len; i++, mlooptri++) { - const int index = mlooptri->poly; - const float *cos[3] = {mr->mvert[mr->mloop[mlooptri->tri[0]].v].co, - mr->mvert[mr->mloop[mlooptri->tri[1]].v].co, - mr->mvert[mr->mloop[mlooptri->tri[2]].v].co}; - float ray_co[3]; - float ray_no[3]; - - normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); - - for (int j = 0; j < samples; j++) { - interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]); - madd_v3_v3fl(ray_co, ray_no, eps_offset); - - BVHTreeRayHit hit; - hit.index = -1; - hit.dist = face_dists[index]; - if ((BLI_bvhtree_ray_cast( - tree, ray_co, ray_no, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) && - hit.dist < face_dists[index]) { - float angle_fac = fabsf(dot_v3v3(mr->poly_normals[index], hit.no)); - angle_fac = 1.0f - angle_fac; - angle_fac = angle_fac * angle_fac * angle_fac; - angle_fac = 1.0f - angle_fac; - hit.dist /= angle_fac; - if (hit.dist < face_dists[index]) { - face_dists[index] = hit.dist; - } - } - } - } - - const MPoly *mp = mr->mpoly; - for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - float fac = face_dists[mp_index]; - fac = thickness_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mp->totloop; i++, l_index++) { - r_thickness[l_index] = fac; - } - } - } -} - -struct BVHTree_OverlapData { - const Mesh *me; - const MLoopTri *mlooptri; - float epsilon; -}; - -static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) -{ - struct BVHTree_OverlapData *data = userdata; - const Mesh *me = data->me; - - const MLoopTri *tri_a = &data->mlooptri[index_a]; - const MLoopTri *tri_b = &data->mlooptri[index_b]; - - if (UNLIKELY(tri_a->poly == tri_b->poly)) { - return false; - } - - const float *tri_a_co[3] = {me->mvert[me->mloop[tri_a->tri[0]].v].co, - me->mvert[me->mloop[tri_a->tri[1]].v].co, - me->mvert[me->mloop[tri_a->tri[2]].v].co}; - const float *tri_b_co[3] = {me->mvert[me->mloop[tri_b->tri[0]].v].co, - me->mvert[me->mloop[tri_b->tri[1]].v].co, - me->mvert[me->mloop[tri_b->tri[2]].v].co}; - float ix_pair[2][3]; - int verts_shared = 0; - - verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) + - ELEM(tri_a_co[2], UNPACK3(tri_b_co))); - - /* if 2 points are shared, bail out */ - if (verts_shared >= 2) { - return false; - } - - return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) && - /* if we share a vertex, check the intersection isn't a 'point' */ - ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon))); -} - -static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) -{ - BMEditMesh *em = mr->edit_bmesh; - - for (int l_index = 0; l_index < mr->loop_len; l_index++) { - r_intersect[l_index] = -1.0f; - } - - if (mr->extract_type == MR_EXTRACT_BMESH) { - uint overlap_len; - BMesh *bm = em->bm; - - BM_mesh_elem_index_ensure(bm, BM_FACE); - - struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false); - BVHTreeOverlap *overlap = BKE_bmbvh_overlap_self(bmtree, &overlap_len); - - if (overlap) { - for (int i = 0; i < overlap_len; i++) { - BMFace *f_hit_pair[2] = { - em->looptris[overlap[i].indexA][0]->f, - em->looptris[overlap[i].indexB][0]->f, - }; - for (int j = 0; j < 2; j++) { - BMFace *f_hit = f_hit_pair[j]; - BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit); - int l_index = BM_elem_index_get(l_first); - for (int k = 0; k < f_hit->len; k++, l_index++) { - r_intersect[l_index] = 1.0f; - } - } - } - MEM_freeN(overlap); - } - - BKE_bmbvh_free(bmtree); - } - else { - uint overlap_len; - BVHTreeFromMesh treeData = {NULL}; - - BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4); - - struct BVHTree_OverlapData data = { - .me = mr->me, .mlooptri = mr->mlooptri, .epsilon = BLI_bvhtree_get_epsilon(tree)}; - - BVHTreeOverlap *overlap = BLI_bvhtree_overlap(tree, tree, &overlap_len, bvh_overlap_cb, &data); - if (overlap) { - for (int i = 0; i < overlap_len; i++) { - const MPoly *f_hit_pair[2] = { - &mr->mpoly[mr->mlooptri[overlap[i].indexA].poly], - &mr->mpoly[mr->mlooptri[overlap[i].indexB].poly], - }; - for (int j = 0; j < 2; j++) { - const MPoly *f_hit = f_hit_pair[j]; - int l_index = f_hit->loopstart; - for (int k = 0; k < f_hit->totloop; k++, l_index++) { - r_intersect[l_index] = 1.0f; - } - } - } - MEM_freeN(overlap); - } - } -} - -BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange) -{ - if (fac >= min) { - fac = (fac - min) * minmax_irange; - CLAMP(fac, 0.0f, 1.0f); - } - else { - /* fallback */ - fac = -1.0f; - } - return fac; -} - -static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) -{ - BMEditMesh *em = mr->edit_bmesh; - const MeshStatVis *statvis = &mr->toolsettings->statvis; - const float min = statvis->distort_min; - const float max = statvis->distort_max; - const float minmax_irange = 1.0f / (max - min); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMesh *bm = em->bm; - BMFace *f; - - if (mr->bm_vert_coords != NULL) { - BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data); - - /* Most likely this is already valid, ensure just in case. - * Needed for #BM_loop_calc_face_normal_safe_vcos. */ - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - } - - int l_index = 0; - int f_index = 0; - BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) { - float fac = -1.0f; - - if (f->len > 3) { - BMLoop *l_iter, *l_first; - - fac = 0.0f; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const float *no_face; - float no_corner[3]; - if (mr->bm_vert_coords != NULL) { - no_face = mr->bm_poly_normals[f_index]; - BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); - } - else { - no_face = f->no; - BM_loop_calc_face_normal_safe(l_iter, no_corner); - } - - /* simple way to detect (what is most likely) concave */ - if (dot_v3v3(no_face, no_corner) < 0.0f) { - negate_v3(no_corner); - } - fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner)); - - } while ((l_iter = l_iter->next) != l_first); - fac *= 2.0f; - } - - fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < f->len; i++, l_index++) { - r_distort[l_index] = fac; - } - } - } - else { - const MPoly *mp = mr->mpoly; - for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - float fac = -1.0f; - - if (mp->totloop > 3) { - float *f_no = mr->poly_normals[mp_index]; - fac = 0.0f; - - for (int i = 1; i <= mp->totloop; i++) { - const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop]; - const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; - const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; - float no_corner[3]; - normal_tri_v3(no_corner, - mr->mvert[l_prev->v].co, - mr->mvert[l_curr->v].co, - mr->mvert[l_next->v].co); - /* simple way to detect (what is most likely) concave */ - if (dot_v3v3(f_no, no_corner) < 0.0f) { - negate_v3(no_corner); - } - fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner)); - } - fac *= 2.0f; - } - - fac = distort_remap(fac, min, max, minmax_irange); - for (int i = 0; i < mp->totloop; i++, l_index++) { - r_distort[l_index] = fac; - } - } - } -} - -BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange) -{ - /* important not '>=' */ - if (fac > min) { - fac = (fac - min) * minmax_irange; - CLAMP(fac, 0.0f, 1.0f); - } - else { - /* fallback */ - fac = -1.0f; - } - return fac; -} - -static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) -{ - BMEditMesh *em = mr->edit_bmesh; - const MeshStatVis *statvis = &mr->toolsettings->statvis; - const float min = statvis->sharp_min; - const float max = statvis->sharp_max; - const float minmax_irange = 1.0f / (max - min); - - /* Can we avoid this extra allocation? */ - float *vert_angles = MEM_mallocN(sizeof(float) * mr->vert_len, __func__); - copy_vn_fl(vert_angles, mr->vert_len, -M_PI); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMesh *bm = em->bm; - BMFace *efa; - BMEdge *e; - /* first assign float values to verts */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - float angle = BM_edge_calc_face_angle_signed(e); - float *col1 = &vert_angles[BM_elem_index_get(e->v1)]; - float *col2 = &vert_angles[BM_elem_index_get(e->v2)]; - *col1 = max_ff(*col1, angle); - *col2 = max_ff(*col2, angle); - } - /* Copy vert value to loops. */ - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - int l_index = BM_elem_index_get(l_iter); - int v_index = BM_elem_index_get(l_iter->v); - r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange); - } while ((l_iter = l_iter->next) != l_first); - } - } - else { - /* first assign float values to verts */ - const MPoly *mp = mr->mpoly; - - EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len); - - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - for (int i = 0; i < mp->totloop; i++) { - const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; - const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; - const MVert *v_curr = &mr->mvert[l_curr->v]; - const MVert *v_next = &mr->mvert[l_next->v]; - float angle; - void **pval; - bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval); - if (!value_is_init) { - *pval = mr->poly_normals[mp_index]; - /* non-manifold edge, yet... */ - continue; - } - if (*pval != NULL) { - const float *f1_no = mr->poly_normals[mp_index]; - const float *f2_no = *pval; - angle = angle_normalized_v3v3(f1_no, f2_no); - angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle; - /* Tag as manifold. */ - *pval = NULL; - } - else { - /* non-manifold edge */ - angle = DEG2RADF(90.0f); - } - float *col1 = &vert_angles[l_curr->v]; - float *col2 = &vert_angles[l_next->v]; - *col1 = max_ff(*col1, angle); - *col2 = max_ff(*col2, angle); - } - } - /* Remaining non manifold edges. */ - EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh); - for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { - if (BLI_edgehashIterator_getValue(ehi) != NULL) { - uint v1, v2; - const float angle = DEG2RADF(90.0f); - BLI_edgehashIterator_getKey(ehi, &v1, &v2); - float *col1 = &vert_angles[v1]; - float *col2 = &vert_angles[v2]; - *col1 = max_ff(*col1, angle); - *col2 = max_ff(*col2, angle); - } - } - BLI_edgehashIterator_free(ehi); - BLI_edgehash_free(eh, NULL); - - const MLoop *ml = mr->mloop; - for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) { - r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange); - } - } - - MEM_freeN(vert_angles); -} - -static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(data)) -{ - GPUVertBuf *vbo = buf; - BLI_assert(mr->edit_bmesh); - - float *l_weight = (float *)GPU_vertbuf_get_data(vbo); - - switch (mr->toolsettings->statvis.type) { - case SCE_STATVIS_OVERHANG: - statvis_calc_overhang(mr, l_weight); - break; - case SCE_STATVIS_THICKNESS: - statvis_calc_thickness(mr, l_weight); - break; - case SCE_STATVIS_INTERSECT: - statvis_calc_intersect(mr, l_weight); - break; - case SCE_STATVIS_DISTORT: - statvis_calc_distort(mr, l_weight); - break; - case SCE_STATVIS_SHARP: - statvis_calc_sharp(mr, l_weight); - break; - } -} - -const MeshExtract extract_mesh_analysis = { - .init = extract_mesh_analysis_init, - .finish = extract_analysis_iter_finish_mesh, - /* This is not needed for all visualization types. - * * Maybe split into different extract. */ - .data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Face-dots positions - * \{ */ - -static void extract_fdots_pos_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); - *(float(**)[3])tls_data = GPU_vertbuf_get_data(vbo); -} - -static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int f_index, - void *data) -{ - float(*center)[3] = *(float(**)[3])data; - - float *co = center[f_index]; - zero_v3(co); - - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - add_v3_v3(co, bm_vert_co_get(mr, l_iter->v)); - } while ((l_iter = l_iter->next) != l_first); - mul_v3_fl(co, 1.0f / (float)f->len); -} - -static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *data) -{ - float(*center)[3] = *(float(**)[3])data; - float *co = center[mp_index]; - zero_v3(co); - - const MVert *mvert = mr->mvert; - const MLoop *mloop = mr->mloop; - - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - if (mr->use_subsurf_fdots) { - const MVert *mv = &mr->mvert[ml->v]; - if (mv->flag & ME_VERT_FACEDOT) { - copy_v3_v3(center[mp_index], mv->co); - break; - } - } - else { - const MVert *mv = &mvert[ml->v]; - add_v3_v3(center[mp_index], mv->co); - } - } - - if (!mr->use_subsurf_fdots) { - mul_v3_fl(co, 1.0f / (float)mp->totloop); - } -} - -const MeshExtract extract_fdots_pos = { - .init = extract_fdots_pos_init, - .iter_poly_bm = extract_fdots_pos_iter_poly_bm, - .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(float (*)[3]), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Face-dots Normal and edit flag - * \{ */ -#define NOR_AND_FLAG_DEFAULT 0 -#define NOR_AND_FLAG_SELECT 1 -#define NOR_AND_FLAG_ACTIVE -1 -#define NOR_AND_FLAG_HIDDEN -2 - -static void extract_fdots_nor_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); -} - -static void extract_fdots_nor_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(data)) -{ - GPUVertBuf *vbo = buf; - static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; - GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo); - BMFace *efa; - - /* Quicker than doing it for each loop. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - for (int f = 0; f < mr->poly_len; f++) { - efa = BM_face_at_index(mr->bm, f); - const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { - nor[f] = GPU_normal_convert_i10_v3(invalid_normal); - nor[f].w = NOR_AND_FLAG_HIDDEN; - } - else { - nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); - /* Select / Active Flag. */ - nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? - ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : - NOR_AND_FLAG_DEFAULT); - } - } - } - else { - for (int f = 0; f < mr->poly_len; f++) { - efa = bm_original_face_get(mr, f); - const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { - nor[f] = GPU_normal_convert_i10_v3(invalid_normal); - nor[f].w = NOR_AND_FLAG_HIDDEN; - } - else { - nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); - /* Select / Active Flag. */ - nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? - ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : - NOR_AND_FLAG_DEFAULT); - } - } - } -} - -const MeshExtract extract_fdots_nor = { - .init = extract_fdots_nor_init, - .finish = extract_fdots_nor_finish, - .data_type = MR_DATA_POLY_NOR, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Face-dots High Quality Normal and edit flag - * \{ */ -static void extract_fdots_nor_hq_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); -} - -static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(data)) -{ - GPUVertBuf *vbo = buf; - static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; - short *nor = (short *)GPU_vertbuf_get_data(vbo); - BMFace *efa; - - /* Quicker than doing it for each loop. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - for (int f = 0; f < mr->poly_len; f++) { - efa = BM_face_at_index(mr->bm, f); - const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { - normal_float_to_short_v3(&nor[f * 4], invalid_normal); - nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; - } - else { - normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa)); - /* Select / Active Flag. */ - nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? - ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : - NOR_AND_FLAG_DEFAULT); - } - } - } - else { - for (int f = 0; f < mr->poly_len; f++) { - efa = bm_original_face_get(mr, f); - const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); - if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && - mr->p_origindex[f] == ORIGINDEX_NONE)) { - normal_float_to_short_v3(&nor[f * 4], invalid_normal); - nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; - } - else { - normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa)); - /* Select / Active Flag. */ - nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? - ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : - NOR_AND_FLAG_DEFAULT); - } - } - } -} - -const MeshExtract extract_fdots_nor_hq = { - .init = extract_fdots_nor_hq_init, - .finish = extract_fdots_nor_hq_finish, - .data_type = MR_DATA_POLY_NOR, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Face-dots UV - * \{ */ - -typedef struct MeshExtract_FdotUV_Data { - float (*vbo_data)[2]; - MLoopUV *uv_data; - int cd_ofs; -} MeshExtract_FdotUV_Data; - -static void extract_fdots_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - GPU_vertformat_alias_add(&format, "au"); - GPU_vertformat_alias_add(&format, "pos"); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); - - if (!mr->use_subsurf_fdots) { - /* Clear so we can accumulate on it. */ - memset(GPU_vertbuf_get_data(vbo), 0x0, mr->poly_len * GPU_vertbuf_get_format(vbo)->stride); - } - - MeshExtract_FdotUV_Data *data = tls_data; - data->vbo_data = (float(*)[2])GPU_vertbuf_get_data(vbo); - - if (mr->extract_type == MR_EXTRACT_BMESH) { - data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); - } - else { - data->uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); - } -} - -static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_FdotUV_Data *data = _data; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - float w = 1.0f / (float)f->len; - const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); - madd_v2_v2fl(data->vbo_data[BM_elem_index_get(f)], luv->uv, w); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *_data) -{ - MeshExtract_FdotUV_Data *data = _data; - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - if (mr->use_subsurf_fdots) { - const MVert *mv = &mr->mvert[ml->v]; - if (mv->flag & ME_VERT_FACEDOT) { - copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv); - } - } - else { - float w = 1.0f / (float)mp->totloop; - madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); - } - } -} - -const MeshExtract extract_fdots_uv = { - .init = extract_fdots_uv_init, - .iter_poly_bm = extract_fdots_uv_iter_poly_bm, - .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_FdotUV_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Face-dots Edit UV flag - * \{ */ - -typedef struct MeshExtract_EditUVFdotData_Data { - EditLoopData *vbo_data; - int cd_ofs; -} MeshExtract_EditUVFdotData_Data; - -static void extract_fdots_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); - - MeshExtract_EditUVFdotData_Data *data = tls_data; - data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); - data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); -} - -static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, - const BMFace *f, - const int UNUSED(f_index), - void *_data) -{ - MeshExtract_EditUVFdotData_Data *data = _data; - EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; - memset(eldata, 0x0, sizeof(*eldata)); - mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); -} - -static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *UNUSED(mp), - const int mp_index, - void *_data) -{ - MeshExtract_EditUVFdotData_Data *data = _data; - EditLoopData *eldata = &data->vbo_data[mp_index]; - memset(eldata, 0x0, sizeof(*eldata)); - BMFace *efa = bm_original_face_get(mr, mp_index); - if (efa) { - mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); - } -} - -const MeshExtract extract_fdots_edituv_data = { - .init = extract_fdots_edituv_data_init, - .iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm, - .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(MeshExtract_EditUVFdotData_Data), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Skin Modifier Roots - * \{ */ - -typedef struct SkinRootData { - float size; - float local_pos[3]; -} SkinRootData; - -static void extract_skin_roots_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *UNUSED(tls_data)) -{ - GPUVertBuf *vbo = buf; - /* Exclusively for edit mode. */ - BLI_assert(mr->bm); - - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->bm->totvert); - - SkinRootData *vbo_data = (SkinRootData *)GPU_vertbuf_get_data(vbo); - - int root_len = 0; - int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN); - - BMIter iter; - BMVert *eve; - BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) { - const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs); - if (vs->flag & MVERT_SKIN_ROOT) { - vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f; - copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve)); - vbo_data++; - root_len++; - } - } - - /* It's really unlikely that all verts will be roots. Resize to avoid losing VRAM. */ - GPU_vertbuf_data_len_set(vbo, root_len); -} - -const MeshExtract extract_skin_roots = { - .init = extract_skin_roots_init, - .data_type = 0, - .data_size = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots)}; - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract Selection Index - * \{ */ - -static void extract_select_idx_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* TODO rename "color" to something more descriptive. */ - GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); - } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); - *(uint32_t **)tls_data = GPU_vertbuf_get_data(vbo); -} - -/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the - * select element associated with this loop ID. This would remove the need for this separate - * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the - * shader to output original index. */ - -static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int f_index, - void *data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - (*(uint32_t **)data)[l_index] = f_index; - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int UNUSED(f_index), - void *data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->e); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *f, - const int UNUSED(f_index), - void *data) -{ - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - const int l_index = BM_elem_index_get(l_iter); - (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->v); - } while ((l_iter = l_iter->next) != l_first); -} - -static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *eed, - const int ledge_index, - void *data) -{ - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); -} - -static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, - const BMEdge *eed, - const int ledge_index, - void *data) -{ - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); -} - -static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, - const BMVert *eve, - const int lvert_index, - void *data) -{ - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - (*(uint32_t **)data)[offset + lvert_index] = BM_elem_index_get(eve); -} - -static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int mp_index, - void *data) -{ - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - (*(uint32_t **)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; - } -} - -static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *data) -{ - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - (*(uint32_t **)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; - } -} - -static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *mp, - const int UNUSED(mp_index), - void *data) -{ - const MLoop *mloop = mr->mloop; - const int ml_index_end = mp->loopstart + mp->totloop; - for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { - const MLoop *ml = &mloop[ml_index]; - (*(uint32_t **)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; - } -} - -static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *UNUSED(med), - const int ledge_index, - void *data) -{ - const int e_index = mr->ledges[ledge_index]; - const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; -} - -static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, - const MEdge *med, - const int ledge_index, - void *data) -{ - int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; - int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; - (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; -} - -static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, - const MVert *UNUSED(mv), - const int lvert_index, - void *data) -{ - const int offset = mr->loop_len + (mr->edge_loose_len * 2); - - const int v_index = mr->lverts[lvert_index]; - const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; - (*(uint32_t **)data)[offset + lvert_index] = v_orig; -} - -const MeshExtract extract_poly_idx = { - .init = extract_select_idx_init, - .iter_poly_bm = extract_poly_idx_iter_poly_bm, - .iter_poly_mesh = extract_poly_idx_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(uint32_t *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx)}; - -const MeshExtract extract_edge_idx = { - .init = extract_select_idx_init, - .iter_poly_bm = extract_edge_idx_iter_poly_bm, - .iter_poly_mesh = extract_edge_idx_iter_poly_mesh, - .iter_ledge_bm = extract_edge_idx_iter_ledge_bm, - .iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh, - .data_type = 0, - .data_size = sizeof(uint32_t *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx)}; - -const MeshExtract extract_vert_idx = { - .init = extract_select_idx_init, - .iter_poly_bm = extract_vert_idx_iter_poly_bm, - .iter_poly_mesh = extract_vert_idx_iter_poly_mesh, - .iter_ledge_bm = extract_vert_idx_iter_ledge_bm, - .iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh, - .iter_lvert_bm = extract_vert_idx_iter_lvert_bm, - .iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh, - .data_type = 0, - .data_size = sizeof(uint32_t *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx)}; - -static void extract_fdot_idx_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) -{ - GPUVertBuf *vbo = buf; - static GPUVertFormat format = {0}; - if (format.attr_len == 0) { - /* TODO rename "color" to something more descriptive. */ - GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); - } - - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->poly_len); - *(uint32_t **)tls_data = GPU_vertbuf_get_data(vbo); -} - -static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), - const BMFace *UNUSED(f), - const int f_index, - void *data) -{ - (*(uint32_t **)data)[f_index] = f_index; -} - -static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, - const MPoly *UNUSED(mp), - const int mp_index, - void *data) -{ - if (mr->p_origindex != NULL) { - (*(uint32_t **)data)[mp_index] = mr->p_origindex[mp_index]; - } - else { - (*(uint32_t **)data)[mp_index] = mp_index; - } -} - -const MeshExtract extract_fdot_idx = { - .init = extract_fdot_idx_init, - .iter_poly_bm = extract_fdot_idx_iter_poly_bm, - .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh, - .data_type = 0, - .data_size = sizeof(uint32_t *), - .use_threading = true, - .mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx)}; diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h index 1b4521335ec..2424b0f9fee 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -258,11 +258,30 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRDataType data_flag); /* draw_cache_extract_mesh_extractors.c */ +typedef struct EditLoopData { + uchar v_flag; + uchar e_flag; + uchar crease; + uchar bweight; +} EditLoopData; + void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc); eMRIterType mesh_extract_iter_type(const MeshExtract *ext); const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, const bool do_hq_normals, const bool do_single_mat); +void mesh_render_data_face_flag(const MeshRenderData *mr, + const BMFace *efa, + const int cd_ofs, + EditLoopData *eattr); +void mesh_render_data_loop_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr); +void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, + BMLoop *l, + const int cd_ofs, + EditLoopData *eattr); extern const MeshExtract extract_tris; extern const MeshExtract extract_tris_single_mat; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc new file mode 100644 index 00000000000..7033a2b509a --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -0,0 +1,241 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "GPU_capabilities.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edge Factor + * Defines how much an edge is visible. + * \{ */ + +typedef struct MeshExtract_EdgeFac_Data { + uchar *vbo_data; + bool use_edge_render; + /* Number of loop per edge. */ + uchar *edge_loop_count; +} MeshExtract_EdgeFac_Data; + +static float loop_edge_factor_get(const float f_no[3], + const float v_co[3], + const float v_no[3], + const float v_next_co[3]) +{ + float enor[3], evec[3]; + sub_v3_v3v3(evec, v_next_co, v_co); + cross_v3_v3v3(enor, v_no, evec); + normalize_v3(enor); + float d = fabsf(dot_v3v3(enor, f_no)); + /* Re-scale to the slider range. */ + d *= (1.0f / 0.065f); + CLAMP(d, 0.0f, 1.0f); + return d; +} + +static void extract_edge_fac_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); + + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(tls_data); + + if (mr->extract_type == MR_EXTRACT_MESH) { + data->edge_loop_count = static_cast<uchar *>( + MEM_callocN(sizeof(uint32_t) * mr->edge_len, __func__)); + + /* HACK(fclem) Detecting the need for edge render. + * We could have a flag in the mesh instead or check the modifier stack. */ + const MEdge *med = mr->medge; + for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) { + if ((med->flag & ME_EDGERENDER) == 0) { + data->use_edge_render = true; + break; + } + } + } + else { + /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */ + data->use_edge_render = true; + } + + data->vbo_data = static_cast<uchar *>(GPU_vertbuf_get_data(vbo)); +} + +static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + if (BM_edge_is_manifold(l_iter->e)) { + float ratio = loop_edge_factor_get(bm_face_no_get(mr, f), + bm_vert_co_get(mr, l_iter->v), + bm_vert_no_get(mr, l_iter->v), + bm_vert_co_get(mr, l_iter->next->v)); + data->vbo_data[l_index] = ratio * 253 + 1; + } + else { + data->vbo_data[l_index] = 255; + } + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *_data) +{ + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data); + + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + + if (data->use_edge_render) { + const MEdge *med = &mr->medge[ml->e]; + data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0; + } + else { + + /* Count loop per edge to detect non-manifold. */ + if (data->edge_loop_count[ml->e] < 3) { + data->edge_loop_count[ml->e]++; + } + if (data->edge_loop_count[ml->e] == 2) { + /* Manifold */ + const int ml_index_last = mp->totloop + mp->loopstart - 1; + const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1); + const MLoop *ml_next = &mr->mloop[ml_index_other]; + const MVert *v1 = &mr->mvert[ml->v]; + const MVert *v2 = &mr->mvert[ml_next->v]; + float vnor_f[3]; + normal_short_to_float_v3(vnor_f, v1->no); + float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co); + data->vbo_data[ml_index] = ratio * 253 + 1; + } + else { + /* Non-manifold */ + data->vbo_data[ml_index] = 255; + } + } + } +} + +static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *UNUSED(eed), + const int ledge_index, + void *_data) +{ + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data); + data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255; + data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255; +} + +static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *UNUSED(med), + const int ledge_index, + void *_data) +{ + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data); + + data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255; + data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255; +} + +static void extract_edge_fac_finish(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data); + + if (GPU_crappy_amd_driver()) { + /* Some AMD drivers strangely crash with VBO's with a one byte format. + * To workaround we reinitialize the VBO with another format and convert + * all bytes to floats. */ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + /* We keep the data reference in data->vbo_data. */ + data->vbo_data = static_cast<uchar *>(GPU_vertbuf_steal_data(vbo)); + GPU_vertbuf_clear(vbo); + + int buf_len = mr->loop_len + mr->loop_loose_len; + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, buf_len); + + float *fdata = (float *)GPU_vertbuf_get_data(vbo); + for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) { + *fdata = data->vbo_data[ml_index] / 255.0f; + } + /* Free old byte data. */ + MEM_freeN(data->vbo_data); + } + MEM_SAFE_FREE(data->edge_loop_count); +} + +constexpr MeshExtract create_extractor_edge_fac() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_edge_fac_init; + extractor.iter_poly_bm = extract_edge_fac_iter_poly_bm; + extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh; + extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh; + extractor.finish = extract_edge_fac_finish; + extractor.data_type = MR_DATA_POLY_NOR; + extractor.data_size = sizeof(MeshExtract_EdgeFac_Data); + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_fac); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc new file mode 100644 index 00000000000..ff250a30ec4 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -0,0 +1,265 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" +#include "draw_cache_impl.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit Mode Data / Flags + * \{ */ + +static void mesh_render_data_edge_flag(const MeshRenderData *mr, + const BMEdge *eed, + EditLoopData *eattr) +{ + const ToolSettings *ts = mr->toolsettings; + const bool is_vertex_select_mode = (ts != nullptr) && (ts->selectmode & SCE_SELECT_VERTEX) != 0; + const bool is_face_only_select_mode = (ts != nullptr) && (ts->selectmode == SCE_SELECT_FACE); + + if (eed == mr->eed_act) { + eattr->e_flag |= VFLAG_EDGE_ACTIVE; + } + if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + eattr->e_flag |= VFLAG_EDGE_SELECTED; + } + if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) { + eattr->e_flag |= VFLAG_EDGE_SELECTED; + eattr->e_flag |= VFLAG_VERT_SELECTED; + } + if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) { + eattr->e_flag |= VFLAG_EDGE_SEAM; + } + if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) { + eattr->e_flag |= VFLAG_EDGE_SHARP; + } + + /* Use active edge color for active face edges because + * specular highlights make it hard to see T55456#510873. + * + * This isn't ideal since it can't be used when mixing edge/face modes + * but it's still better than not being able to see the active face. */ + if (is_face_only_select_mode) { + if (mr->efa_act != nullptr) { + if (BM_edge_in_face(eed, mr->efa_act)) { + eattr->e_flag |= VFLAG_EDGE_ACTIVE; + } + } + } + + /* Use a byte for value range */ + if (mr->crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs); + if (crease > 0) { + eattr->crease = (uchar)(crease * 255.0f); + } + } + /* Use a byte for value range */ + if (mr->bweight_ofs != -1) { + float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs); + if (bweight > 0) { + eattr->bweight = (uchar)(bweight * 255.0f); + } + } +#ifdef WITH_FREESTYLE + if (mr->freestyle_edge_ofs != -1) { + const FreestyleEdge *fed = (const FreestyleEdge *)BM_ELEM_CD_GET_VOID_P( + eed, mr->freestyle_edge_ofs); + if (fed->flag & FREESTYLE_EDGE_MARK) { + eattr->e_flag |= VFLAG_EDGE_FREESTYLE; + } + } +#endif +} + +static void mesh_render_data_vert_flag(const MeshRenderData *mr, + const BMVert *eve, + EditLoopData *eattr) +{ + if (eve == mr->eve_act) { + eattr->e_flag |= VFLAG_VERT_ACTIVE; + } + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + eattr->e_flag |= VFLAG_VERT_SELECTED; + } +} + +static void extract_edit_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* WARNING: Adjust #EditLoopData struct accordingly. */ + GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); + GPU_vertformat_alias_add(&format, "flag"); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); + EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + *(EditLoopData **)tls_data = vbo_data; +} + +static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + EditLoopData *data = vbo_data + l_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_face_flag(mr, f, -1, data); + mesh_render_data_edge_flag(mr, l_iter->e, data); + mesh_render_data_vert_flag(mr, l_iter->v, data); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + EditLoopData *data = vbo_data + ml_index; + memset(data, 0x0, sizeof(*data)); + BMFace *efa = bm_original_face_get(mr, mp_index); + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (efa) { + mesh_render_data_face_flag(mr, efa, -1, data); + } + if (eed) { + mesh_render_data_edge_flag(mr, eed, data); + } + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } + } +} + +static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *eed, + const int ledge_index, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + EditLoopData *data = vbo_data + mr->loop_len + (ledge_index * 2); + memset(data, 0x0, sizeof(*data) * 2); + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); +} + +static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *med, + const int ledge_index, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + EditLoopData *data = vbo_data + mr->loop_len + ledge_index * 2; + memset(data, 0x0, sizeof(*data) * 2); + const int e_index = mr->ledges[ledge_index]; + BMEdge *eed = bm_original_edge_get(mr, e_index); + BMVert *eve1 = bm_original_vert_get(mr, med->v1); + BMVert *eve2 = bm_original_vert_get(mr, med->v2); + if (eed) { + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + } + if (eve1) { + mesh_render_data_vert_flag(mr, eve1, &data[0]); + } + if (eve2) { + mesh_render_data_vert_flag(mr, eve2, &data[1]); + } +} + +static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, + const BMVert *eve, + const int lvert_index, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + EditLoopData *data = vbo_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + mesh_render_data_vert_flag(mr, eve, data); +} + +static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, + const MVert *UNUSED(mv), + const int lvert_index, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + EditLoopData *data = vbo_data + offset + lvert_index; + memset(data, 0x0, sizeof(*data)); + const int v_index = mr->lverts[lvert_index]; + BMVert *eve = bm_original_vert_get(mr, v_index); + if (eve) { + mesh_render_data_vert_flag(mr, eve, data); + } +} + +constexpr MeshExtract create_extractor_edit_data() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_edit_data_init; + extractor.iter_poly_bm = extract_edit_data_iter_poly_bm; + extractor.iter_poly_mesh = extract_edit_data_iter_poly_mesh; + extractor.iter_ledge_bm = extract_edit_data_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh; + extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm; + extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(EditLoopData *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edit_data); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc new file mode 100644 index 00000000000..d4a72000fc1 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -0,0 +1,140 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" +#include "draw_cache_impl.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit UV Data / Flags + * \{ */ + +typedef struct MeshExtract_EditUVData_Data { + EditLoopData *vbo_data; + int cd_ofs; +} MeshExtract_EditUVData_Data; + +static void extract_edituv_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* WARNING: Adjust #EditLoopData struct accordingly. */ + GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); + GPU_vertformat_alias_add(&format, "flag"); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); +} + +static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data); + EditLoopData *eldata = &data->vbo_data[l_index]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_loop_flag(mr, l_iter, data->cd_ofs, eldata); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l_iter, data->cd_ofs, eldata); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *_data) +{ + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data); + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + + EditLoopData *eldata = &data->vbo_data[ml_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + BMEdge *eed = bm_original_edge_get(mr, ml->e); + BMVert *eve = bm_original_vert_get(mr, ml->v); + if (eed && eve) { + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } + else { + if (eed == nullptr) { + /* Find if the loop's vert is not part of an edit edge. + * For this, we check if the previous loop was on an edge. */ + const int ml_index_last = mp->loopstart + mp->totloop - 1; + const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1); + const MLoop *ml_prev = &mr->mloop[l_prev]; + eed = bm_original_edge_get(mr, ml_prev->e); + } + if (eed) { + /* Mapped points on an edge between two edit verts. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata); + } + } + } + } +} + +constexpr MeshExtract create_extractor_edituv_data() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_edituv_data_init; + extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm; + extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_EditUVData_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_data); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc new file mode 100644 index 00000000000..63b52a4ad9a --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -0,0 +1,236 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_mesh.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit UV angle stretch + * \{ */ + +typedef struct UVStretchAngle { + int16_t angle; + int16_t uv_angles[2]; +} UVStretchAngle; + +typedef struct MeshExtract_StretchAngle_Data { + UVStretchAngle *vbo_data; + MLoopUV *luv; + float auv[2][2], last_auv[2]; + float av[2][3], last_av[3]; + int cd_ofs; +} MeshExtract_StretchAngle_Data; + +static void compute_normalize_edge_vectors(float auv[2][2], + float av[2][3], + const float uv[2], + const float uv_prev[2], + const float co[3], + const float co_prev[3]) +{ + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* 2d edge */ + sub_v2_v2v2(auv[1], uv_prev, uv); + normalize_v2(auv[1]); + /* 3d edge */ + sub_v3_v3v3(av[1], co_prev, co); + normalize_v3(av[1]); +} + +static short v2_to_short_angle(const float v[2]) +{ + return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX; +} + +static void edituv_get_edituv_stretch_angle(float auv[2][2], + const float av[2][3], + UVStretchAngle *r_stretch) +{ + /* Send UV's to the shader and let it compute the aspect corrected angle. */ + r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]); + r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]); + /* Compute 3D angle here. */ + r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX; + +#if 0 /* here for reference, this is done in shader now. */ + float uvang = angle_normalized_v2v2(auv0, auv1); + float ang = angle_normalized_v3v3(av0, av1); + float stretch = fabsf(uvang - ang) / (float)M_PI; + return 1.0f - pow2f(1.0f - stretch); +#endif +} + +static void extract_edituv_stretch_angle_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* Waning: adjust #UVStretchAngle struct accordingly. */ + GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + MeshExtract_StretchAngle_Data *data = static_cast<MeshExtract_StretchAngle_Data *>(tls_data); + data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo); + + /* Special iterator needed to save about half of the computing cost. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); + } + else { + BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + data->luv = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); + } +} + +static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_StretchAngle_Data *data = static_cast<MeshExtract_StretchAngle_Data *>(_data); + float(*auv)[2] = data->auv, *last_auv = data->last_auv; + float(*av)[3] = data->av, *last_av = data->last_av; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + + const MLoopUV *luv, *luv_next; + BMLoop *l_next = l_iter->next; + if (l_iter == BM_FACE_FIRST_LOOP(f)) { + /* First loop in face. */ + BMLoop *l_tmp = l_iter->prev; + BMLoop *l_next_tmp = l_iter; + luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs); + luv_next = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_tmp->v), + bm_vert_co_get(mr, l_next_tmp->v)); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == BM_FACE_FIRST_LOOP(f)) { + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); + luv_next = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs); + compute_normalize_edge_vectors(auv, + av, + luv->uv, + luv_next->uv, + bm_vert_co_get(mr, l_iter->v), + bm_vert_co_get(mr, l_next->v)); + } + edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *_data) +{ + MeshExtract_StretchAngle_Data *data = static_cast<MeshExtract_StretchAngle_Data *>(_data); + + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + float(*auv)[2] = data->auv, *last_auv = data->last_auv; + float(*av)[3] = data->av, *last_av = data->last_av; + int l_next = ml_index + 1; + const MVert *v, *v_next; + if (ml_index == mp->loopstart) { + /* First loop in face. */ + const int ml_index_last = ml_index_end - 1; + const int l_next_tmp = mp->loopstart; + v = &mr->mvert[mr->mloop[ml_index_last].v]; + v_next = &mr->mvert[mr->mloop[l_next_tmp].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co); + /* Save last edge. */ + copy_v2_v2(last_auv, auv[1]); + copy_v3_v3(last_av, av[1]); + } + if (l_next == ml_index_end) { + l_next = mp->loopstart; + /* Move previous edge. */ + copy_v2_v2(auv[0], auv[1]); + copy_v3_v3(av[0], av[1]); + /* Copy already calculated last edge. */ + copy_v2_v2(auv[1], last_auv); + copy_v3_v3(av[1], last_av); + } + else { + v = &mr->mvert[mr->mloop[ml_index].v]; + v_next = &mr->mvert[mr->mloop[l_next].v]; + compute_normalize_edge_vectors( + auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co); + } + edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]); + } +} + +constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_edituv_stretch_angle_init; + extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm; + extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_StretchAngle_Data); + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_angle); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_edituv_stretch_angle = + blender::draw::create_extractor_edituv_edituv_stretch_angle(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc new file mode 100644 index 00000000000..16814653408 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -0,0 +1,157 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_mesh.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit UV area stretch + * \{ */ + +static void extract_edituv_stretch_area_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); +} + +BLI_INLINE float area_ratio_get(float area, float uvarea) +{ + if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) { + /* Tag inversion by using the sign. */ + return (area > uvarea) ? (uvarea / area) : -(area / uvarea); + } + return 0.0f; +} + +BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +{ + ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + return (ratio > 1.0f) ? (1.0f / ratio) : ratio; +} + +static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + float tot_area = 0.0f, tot_uv_area = 0.0f; + float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + CustomData *cd_ldata = &mr->bm->ldata; + int uv_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); + + BMFace *efa; + BMIter f_iter; + int f; + BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { + float area = BM_face_calc_area(efa); + float uvarea = BM_face_calc_area_uv(efa, uv_ofs); + tot_area += area; + tot_uv_area += uvarea; + area_ratio[f] = area_ratio_get(area, uvarea); + } + } + else { + BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + const MLoopUV *uv_data = (const MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert); + float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); + tot_area += area; + tot_uv_area += uvarea; + area_ratio[mp_index] = area_ratio_get(area, uvarea); + } + } + + cache->tot_area = tot_area; + cache->tot_uv_area = tot_uv_area; + + /* Convert in place to avoid an extra allocation */ + uint16_t *poly_stretch = (uint16_t *)area_ratio; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX; + } + + /* Copy face data for each loop. */ + uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMFace *efa; + BMIter f_iter; + int f, l_index = 0; + BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) { + for (int i = 0; i < efa->len; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[f]; + } + } + } + else { + BLI_assert(ELEM(mr->extract_type, MR_EXTRACT_MAPPED, MR_EXTRACT_MESH)); + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++, l_index++) { + loop_stretch[l_index] = poly_stretch[mp_index]; + } + } + } + + MEM_freeN(area_ratio); +} + +constexpr MeshExtract create_extractor_edituv_stretch_area() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_edituv_stretch_area_init; + extractor.finish = extract_edituv_stretch_area_finish; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edituv_stretch_area); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_edituv_stretch_area = + blender::draw::create_extractor_edituv_stretch_area(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc new file mode 100644 index 00000000000..dc77f83b30b --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc @@ -0,0 +1,101 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" +#include "draw_cache_impl.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Face-dots Edit UV flag + * \{ */ + +typedef struct MeshExtract_EditUVFdotData_Data { + EditLoopData *vbo_data; + int cd_ofs; +} MeshExtract_EditUVFdotData_Data; + +static void extract_fdots_edituv_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "flag", GPU_COMP_U8, 4, GPU_FETCH_INT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->poly_len); + + MeshExtract_EditUVFdotData_Data *data = static_cast<MeshExtract_EditUVFdotData_Data *>(tls_data); + data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); +} + +static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_EditUVFdotData_Data *data = static_cast<MeshExtract_EditUVFdotData_Data *>(_data); + EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)]; + memset(eldata, 0x0, sizeof(*eldata)); + mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata); +} + +static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *UNUSED(mp), + const int mp_index, + void *_data) +{ + MeshExtract_EditUVFdotData_Data *data = static_cast<MeshExtract_EditUVFdotData_Data *>(_data); + EditLoopData *eldata = &data->vbo_data[mp_index]; + memset(eldata, 0x0, sizeof(*eldata)); + BMFace *efa = bm_original_face_get(mr, mp_index); + if (efa) { + mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata); + } +} + +constexpr MeshExtract create_extractor_fdots_edituv_data() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdots_edituv_data_init; + extractor.iter_poly_bm = extract_fdots_edituv_data_iter_poly_bm; + extractor.iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_EditUVFdotData_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_edituv_data); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc new file mode 100644 index 00000000000..fb9d34e7733 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc @@ -0,0 +1,200 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Face-dots Normal and edit flag + * \{ */ +#define NOR_AND_FLAG_DEFAULT 0 +#define NOR_AND_FLAG_SELECT 1 +#define NOR_AND_FLAG_ACTIVE -1 +#define NOR_AND_FLAG_HIDDEN -2 + +static void extract_fdots_nor_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->poly_len); +} + +static void extract_fdots_nor_finish(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; + GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo); + BMFace *efa; + + /* Quicker than doing it for each loop. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + for (int f = 0; f < mr->poly_len; f++) { + efa = BM_face_at_index(mr->bm, f); + const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); + if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[f] == ORIGINDEX_NONE)) { + nor[f] = GPU_normal_convert_i10_v3(invalid_normal); + nor[f].w = NOR_AND_FLAG_HIDDEN; + } + else { + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); + /* Select / Active Flag. */ + nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? + ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : + NOR_AND_FLAG_DEFAULT); + } + } + } + else { + for (int f = 0; f < mr->poly_len; f++) { + efa = bm_original_face_get(mr, f); + const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); + if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[f] == ORIGINDEX_NONE)) { + nor[f] = GPU_normal_convert_i10_v3(invalid_normal); + nor[f].w = NOR_AND_FLAG_HIDDEN; + } + else { + nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa)); + /* Select / Active Flag. */ + nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? + ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : + NOR_AND_FLAG_DEFAULT); + } + } + } +} + +constexpr MeshExtract create_extractor_fdots_nor() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdots_nor_init; + extractor.finish = extract_fdots_nor_finish; + extractor.data_type = MR_DATA_LOOP_NOR; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor); + return extractor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract Face-dots High Quality Normal and edit flag + * \{ */ +static void extract_fdots_nor_hq_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->poly_len); +} + +static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static float invalid_normal[3] = {0.0f, 0.0f, 0.0f}; + short *nor = (short *)GPU_vertbuf_get_data(vbo); + BMFace *efa; + + /* Quicker than doing it for each loop. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + for (int f = 0; f < mr->poly_len; f++) { + efa = BM_face_at_index(mr->bm, f); + const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN); + if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[f] == ORIGINDEX_NONE)) { + normal_float_to_short_v3(&nor[f * 4], invalid_normal); + nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; + } + else { + normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa)); + /* Select / Active Flag. */ + nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? + ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : + NOR_AND_FLAG_DEFAULT); + } + } + } + else { + for (int f = 0; f < mr->poly_len; f++) { + efa = bm_original_face_get(mr, f); + const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN); + if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex && + mr->p_origindex[f] == ORIGINDEX_NONE)) { + normal_float_to_short_v3(&nor[f * 4], invalid_normal); + nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN; + } + else { + normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa)); + /* Select / Active Flag. */ + nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ? + ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) : + NOR_AND_FLAG_DEFAULT); + } + } + } +} + +constexpr MeshExtract create_extractor_fdots_nor_hq() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdots_nor_hq_init; + extractor.finish = extract_fdots_nor_hq_finish; + extractor.data_type = MR_DATA_LOOP_NOR; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_nor); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor(); +const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc new file mode 100644 index 00000000000..c4706c412c6 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -0,0 +1,119 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Face-dots positions + * \{ */ + +static void extract_fdots_pos_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->poly_len); + void *vbo_data = GPU_vertbuf_get_data(vbo); + *(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data); +} + +static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int f_index, + void *data) +{ + float(*center)[3] = *static_cast<float(**)[3]>(data); + + float *co = center[f_index]; + zero_v3(co); + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + add_v3_v3(co, bm_vert_co_get(mr, l_iter->v)); + } while ((l_iter = l_iter->next) != l_first); + mul_v3_fl(co, 1.0f / (float)f->len); +} + +static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *data) +{ + float(*center)[3] = *static_cast<float(**)[3]>(data); + float *co = center[mp_index]; + zero_v3(co); + + const MVert *mvert = mr->mvert; + const MLoop *mloop = mr->mloop; + + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (mr->use_subsurf_fdots) { + const MVert *mv = &mr->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + copy_v3_v3(center[mp_index], mv->co); + break; + } + } + else { + const MVert *mv = &mvert[ml->v]; + add_v3_v3(center[mp_index], mv->co); + } + } + + if (!mr->use_subsurf_fdots) { + mul_v3_fl(co, 1.0f / (float)mp->totloop); + } +} + +constexpr MeshExtract create_extractor_fdots_pos() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdots_pos_init; + extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm; + extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(float(*)[3]); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_pos); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc new file mode 100644 index 00000000000..1adfe9d00de --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc @@ -0,0 +1,127 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Face-dots UV + * \{ */ + +typedef struct MeshExtract_FdotUV_Data { + float (*vbo_data)[2]; + MLoopUV *uv_data; + int cd_ofs; +} MeshExtract_FdotUV_Data; + +static void extract_fdots_uv_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "u", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "au"); + GPU_vertformat_alias_add(&format, "pos"); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->poly_len); + + if (!mr->use_subsurf_fdots) { + /* Clear so we can accumulate on it. */ + memset(GPU_vertbuf_get_data(vbo), 0x0, mr->poly_len * GPU_vertbuf_get_format(vbo)->stride); + } + + MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(tls_data); + data->vbo_data = (float(*)[2])GPU_vertbuf_get_data(vbo); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV); + } + else { + data->uv_data = (MLoopUV *)CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV); + } +} + +static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(_data); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + float w = 1.0f / (float)f->len; + const MLoopUV *luv = (const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, data->cd_ofs); + madd_v2_v2fl(data->vbo_data[BM_elem_index_get(f)], luv->uv, w); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *_data) +{ + MeshExtract_FdotUV_Data *data = static_cast<MeshExtract_FdotUV_Data *>(_data); + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (mr->use_subsurf_fdots) { + const MVert *mv = &mr->mvert[ml->v]; + if (mv->flag & ME_VERT_FACEDOT) { + copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv); + } + } + else { + float w = 1.0f / (float)mp->totloop; + madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w); + } + } +} + +constexpr MeshExtract create_extractor_fdots_uv() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdots_uv_init; + extractor.iter_poly_bm = extract_fdots_uv_iter_poly_bm; + extractor.iter_poly_mesh = extract_fdots_uv_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_FdotUV_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdots_uv); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc new file mode 100644 index 00000000000..6823cb6e8d0 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -0,0 +1,228 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Loop Normal + * \{ */ + +static void extract_lnor_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_alias_add(&format, "lnor"); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + *(GPUPackedNormal **)tls_data = static_cast<GPUPackedNormal *>(GPU_vertbuf_get_data(vbo)); +} + +static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (mr->loop_normals) { + (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); + } + else { + if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3( + bm_vert_no_get(mr, l_iter->v)); + } + else { + (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, f)); + } + } + (*(GPUPackedNormal **)data)[l_index].w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *data) +{ + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index]; + if (mr->loop_normals) { + *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no); + } + else { + *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]); + } + + /* Flag for paint mode overlay. + * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } + } +} + +constexpr MeshExtract create_extractor_lnor() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_lnor_init; + extractor.iter_poly_bm = extract_lnor_iter_poly_bm; + extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh; + extractor.data_type = MR_DATA_LOOP_NOR; + extractor.data_size = sizeof(GPUPackedNormal *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor); + return extractor; +} + +/** \} */ +/* ---------------------------------------------------------------------- */ +/** \name Extract HQ Loop Normal + * \{ */ + +typedef struct gpuHQNor { + short x, y, z, w; +} gpuHQNor; + +static void extract_lnor_hq_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_alias_add(&format, "lnor"); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + *(gpuHQNor **)tls_data = static_cast<gpuHQNor *>(GPU_vertbuf_get_data(vbo)); +} + +static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (mr->loop_normals) { + normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->loop_normals[l_index]); + } + else { + if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_vert_no_get(mr, l_iter->v)); + } + else { + normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, bm_face_no_get(mr, f)); + } + } + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *data) +{ + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index]; + if (mr->loop_normals) { + normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); + } + else if (mp->flag & ME_SMOOTH) { + copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no); + } + else { + normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]); + } + + /* Flag for paint mode overlay. + * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals. + * In paint mode it will use the un-mapped data to draw the wire-frame. */ + if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED && + (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) { + lnor_data->w = -1; + } + else if (mp->flag & ME_FACE_SEL) { + lnor_data->w = 1; + } + else { + lnor_data->w = 0; + } + } +} + +constexpr MeshExtract create_extractor_lnor_hq() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_lnor_hq_init; + extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm; + extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh; + extractor.data_type = MR_DATA_LOOP_NOR; + extractor.data_size = sizeof(gpuHQNor *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.lnor); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_lnor = blender::draw::create_extractor_lnor(); +const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc new file mode 100644 index 00000000000..b734061b76a --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc @@ -0,0 +1,654 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_edgehash.h" +#include "BLI_jitter_2d.h" + +#include "BKE_bvhutils.h" +#include "BKE_editmesh_bvh.h" +#include "BKE_editmesh_cache.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Edit Mesh Analysis Colors + * \{ */ + +static void extract_mesh_analysis_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); +} + +static void axis_from_enum_v3(float v[3], const char axis) +{ + zero_v3(v); + if (axis < 3) { + v[axis] = 1.0f; + } + else { + v[axis - 3] = -1.0f; + } +} + +BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange) +{ + if (fac < min) { + fac = 1.0f; + } + else if (fac > max) { + fac = -1.0f; + } + else { + fac = (fac - min) * minmax_irange; + fac = 1.0f - fac; + CLAMP(fac, 0.0f, 1.0f); + } + return fac; +} + +static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang) +{ + const MeshStatVis *statvis = &mr->toolsettings->statvis; + const float min = statvis->overhang_min / (float)M_PI; + const float max = statvis->overhang_max / (float)M_PI; + const char axis = statvis->overhang_axis; + BMEditMesh *em = mr->edit_bmesh; + BMIter iter; + BMesh *bm = em->bm; + BMFace *f; + float dir[3]; + const float minmax_irange = 1.0f / (max - min); + + BLI_assert(min <= max); + + axis_from_enum_v3(dir, axis); + + /* now convert into global space */ + mul_transposed_mat3_m4_v3(mr->obmat, dir); + normalize_v3(dir); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + int l_index = 0; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI; + fac = overhang_remap(fac, min, max, minmax_irange); + for (int i = 0; i < f->len; i++, l_index++) { + r_overhang[l_index] = fac; + } + } + } + else { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI; + fac = overhang_remap(fac, min, max, minmax_irange); + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_overhang[l_index] = fac; + } + } + } +} + +/** + * Needed so we can use jitter values for face interpolation. + */ +static void uv_from_jitter_v2(float uv[2]) +{ + uv[0] += 0.5f; + uv[1] += 0.5f; + if (uv[0] + uv[1] > 1.0f) { + uv[0] = 1.0f - uv[0]; + uv[1] = 1.0f - uv[1]; + } + + clamp_v2(uv, 0.0f, 1.0f); +} + +BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange) +{ + /* important not '<=' */ + if (fac < max) { + fac = (fac - min) * minmax_irange; + fac = 1.0f - fac; + CLAMP(fac, 0.0f, 1.0f); + } + else { + fac = -1.0f; + } + return fac; +} + +static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness) +{ + const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */ + /* cheating to avoid another allocation */ + float *face_dists = r_thickness + (mr->loop_len - mr->poly_len); + BMEditMesh *em = mr->edit_bmesh; + const float scale = 1.0f / mat4_to_scale(mr->obmat); + const MeshStatVis *statvis = &mr->toolsettings->statvis; + const float min = statvis->thickness_min * scale; + const float max = statvis->thickness_max * scale; + const float minmax_irange = 1.0f / (max - min); + const int samples = statvis->thickness_samples; + float jit_ofs[32][2]; + BLI_assert(samples <= 32); + BLI_assert(min <= max); + + copy_vn_fl(face_dists, mr->poly_len, max); + + BLI_jitter_init(jit_ofs, samples); + for (int j = 0; j < samples; j++) { + uv_from_jitter_v2(jit_ofs[j]); + } + + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMesh *bm = em->bm; + BM_mesh_elem_index_ensure(bm, BM_FACE); + + struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, nullptr, false); + struct BMLoop *(*looptris)[3] = em->looptris; + for (int i = 0; i < mr->tri_len; i++) { + BMLoop **ltri = looptris[i]; + const int index = BM_elem_index_get(ltri[0]->f); + const float *cos[3] = { + bm_vert_co_get(mr, ltri[0]->v), + bm_vert_co_get(mr, ltri[1]->v), + bm_vert_co_get(mr, ltri[2]->v), + }; + float ray_co[3]; + float ray_no[3]; + + normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); + + for (int j = 0; j < samples; j++) { + float dist = face_dists[index]; + interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]); + madd_v3_v3fl(ray_co, ray_no, eps_offset); + + BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, nullptr, nullptr); + if (f_hit && dist < face_dists[index]) { + float angle_fac = fabsf( + dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit))); + angle_fac = 1.0f - angle_fac; + angle_fac = angle_fac * angle_fac * angle_fac; + angle_fac = 1.0f - angle_fac; + dist /= angle_fac; + if (dist < face_dists[index]) { + face_dists[index] = dist; + } + } + } + } + BKE_bmbvh_free(bmtree); + + BMIter iter; + BMFace *f; + int l_index = 0; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + float fac = face_dists[BM_elem_index_get(f)]; + fac = thickness_remap(fac, min, max, minmax_irange); + for (int i = 0; i < f->len; i++, l_index++) { + r_thickness[l_index] = fac; + } + } + } + else { + BVHTreeFromMesh treeData = {nullptr}; + + BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4); + const MLoopTri *mlooptri = mr->mlooptri; + for (int i = 0; i < mr->tri_len; i++, mlooptri++) { + const int index = mlooptri->poly; + const float *cos[3] = {mr->mvert[mr->mloop[mlooptri->tri[0]].v].co, + mr->mvert[mr->mloop[mlooptri->tri[1]].v].co, + mr->mvert[mr->mloop[mlooptri->tri[2]].v].co}; + float ray_co[3]; + float ray_no[3]; + + normal_tri_v3(ray_no, cos[2], cos[1], cos[0]); + + for (int j = 0; j < samples; j++) { + interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]); + madd_v3_v3fl(ray_co, ray_no, eps_offset); + + BVHTreeRayHit hit; + hit.index = -1; + hit.dist = face_dists[index]; + if ((BLI_bvhtree_ray_cast( + tree, ray_co, ray_no, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) && + hit.dist < face_dists[index]) { + float angle_fac = fabsf(dot_v3v3(mr->poly_normals[index], hit.no)); + angle_fac = 1.0f - angle_fac; + angle_fac = angle_fac * angle_fac * angle_fac; + angle_fac = 1.0f - angle_fac; + hit.dist /= angle_fac; + if (hit.dist < face_dists[index]) { + face_dists[index] = hit.dist; + } + } + } + } + + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = face_dists[mp_index]; + fac = thickness_remap(fac, min, max, minmax_irange); + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_thickness[l_index] = fac; + } + } + } +} + +struct BVHTree_OverlapData { + const Mesh *me; + const MLoopTri *mlooptri; + float epsilon; +}; + +static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) +{ + struct BVHTree_OverlapData *data = static_cast<struct BVHTree_OverlapData *>(userdata); + const Mesh *me = data->me; + + const MLoopTri *tri_a = &data->mlooptri[index_a]; + const MLoopTri *tri_b = &data->mlooptri[index_b]; + + if (UNLIKELY(tri_a->poly == tri_b->poly)) { + return false; + } + + const float *tri_a_co[3] = {me->mvert[me->mloop[tri_a->tri[0]].v].co, + me->mvert[me->mloop[tri_a->tri[1]].v].co, + me->mvert[me->mloop[tri_a->tri[2]].v].co}; + const float *tri_b_co[3] = {me->mvert[me->mloop[tri_b->tri[0]].v].co, + me->mvert[me->mloop[tri_b->tri[1]].v].co, + me->mvert[me->mloop[tri_b->tri[2]].v].co}; + float ix_pair[2][3]; + int verts_shared = 0; + + verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) + + ELEM(tri_a_co[2], UNPACK3(tri_b_co))); + + /* if 2 points are shared, bail out */ + if (verts_shared >= 2) { + return false; + } + + return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) && + /* if we share a vertex, check the intersection isn't a 'point' */ + ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon))); +} + +static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect) +{ + BMEditMesh *em = mr->edit_bmesh; + + for (int l_index = 0; l_index < mr->loop_len; l_index++) { + r_intersect[l_index] = -1.0f; + } + + if (mr->extract_type == MR_EXTRACT_BMESH) { + uint overlap_len; + BMesh *bm = em->bm; + + BM_mesh_elem_index_ensure(bm, BM_FACE); + + struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, nullptr, false); + BVHTreeOverlap *overlap = BKE_bmbvh_overlap_self(bmtree, &overlap_len); + + if (overlap) { + for (int i = 0; i < overlap_len; i++) { + BMFace *f_hit_pair[2] = { + em->looptris[overlap[i].indexA][0]->f, + em->looptris[overlap[i].indexB][0]->f, + }; + for (int j = 0; j < 2; j++) { + BMFace *f_hit = f_hit_pair[j]; + BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit); + int l_index = BM_elem_index_get(l_first); + for (int k = 0; k < f_hit->len; k++, l_index++) { + r_intersect[l_index] = 1.0f; + } + } + } + MEM_freeN(overlap); + } + + BKE_bmbvh_free(bmtree); + } + else { + uint overlap_len; + BVHTreeFromMesh treeData = {nullptr}; + + BVHTree *tree = BKE_bvhtree_from_mesh_get(&treeData, mr->me, BVHTREE_FROM_LOOPTRI, 4); + + struct BVHTree_OverlapData data = {nullptr}; + data.me = mr->me; + data.mlooptri = mr->mlooptri; + data.epsilon = BLI_bvhtree_get_epsilon(tree); + + BVHTreeOverlap *overlap = BLI_bvhtree_overlap(tree, tree, &overlap_len, bvh_overlap_cb, &data); + if (overlap) { + for (int i = 0; i < overlap_len; i++) { + const MPoly *f_hit_pair[2] = { + &mr->mpoly[mr->mlooptri[overlap[i].indexA].poly], + &mr->mpoly[mr->mlooptri[overlap[i].indexB].poly], + }; + for (int j = 0; j < 2; j++) { + const MPoly *f_hit = f_hit_pair[j]; + int l_index = f_hit->loopstart; + for (int k = 0; k < f_hit->totloop; k++, l_index++) { + r_intersect[l_index] = 1.0f; + } + } + } + MEM_freeN(overlap); + } + } +} + +BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange) +{ + if (fac >= min) { + fac = (fac - min) * minmax_irange; + CLAMP(fac, 0.0f, 1.0f); + } + else { + /* fallback */ + fac = -1.0f; + } + return fac; +} + +static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) +{ + BMEditMesh *em = mr->edit_bmesh; + const MeshStatVis *statvis = &mr->toolsettings->statvis; + const float min = statvis->distort_min; + const float max = statvis->distort_max; + const float minmax_irange = 1.0f / (max - min); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMesh *bm = em->bm; + BMFace *f; + + if (mr->bm_vert_coords != nullptr) { + BKE_editmesh_cache_ensure_poly_normals(em, mr->edit_data); + + /* Most likely this is already valid, ensure just in case. + * Needed for #BM_loop_calc_face_normal_safe_vcos. */ + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + } + + int l_index = 0; + int f_index = 0; + BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) { + float fac = -1.0f; + + if (f->len > 3) { + BMLoop *l_iter, *l_first; + + fac = 0.0f; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const float *no_face; + float no_corner[3]; + if (mr->bm_vert_coords != nullptr) { + no_face = mr->bm_poly_normals[f_index]; + BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner); + } + else { + no_face = f->no; + BM_loop_calc_face_normal_safe(l_iter, no_corner); + } + + /* simple way to detect (what is most likely) concave */ + if (dot_v3v3(no_face, no_corner) < 0.0f) { + negate_v3(no_corner); + } + fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner)); + + } while ((l_iter = l_iter->next) != l_first); + fac *= 2.0f; + } + + fac = distort_remap(fac, min, max, minmax_irange); + for (int i = 0; i < f->len; i++, l_index++) { + r_distort[l_index] = fac; + } + } + } + else { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + float fac = -1.0f; + + if (mp->totloop > 3) { + float *f_no = mr->poly_normals[mp_index]; + fac = 0.0f; + + for (int i = 1; i <= mp->totloop; i++) { + const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop]; + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; + float no_corner[3]; + normal_tri_v3(no_corner, + mr->mvert[l_prev->v].co, + mr->mvert[l_curr->v].co, + mr->mvert[l_next->v].co); + /* simple way to detect (what is most likely) concave */ + if (dot_v3v3(f_no, no_corner) < 0.0f) { + negate_v3(no_corner); + } + fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner)); + } + fac *= 2.0f; + } + + fac = distort_remap(fac, min, max, minmax_irange); + for (int i = 0; i < mp->totloop; i++, l_index++) { + r_distort[l_index] = fac; + } + } + } +} + +BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange) +{ + /* important not '>=' */ + if (fac > min) { + fac = (fac - min) * minmax_irange; + CLAMP(fac, 0.0f, 1.0f); + } + else { + /* fallback */ + fac = -1.0f; + } + return fac; +} + +static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) +{ + BMEditMesh *em = mr->edit_bmesh; + const MeshStatVis *statvis = &mr->toolsettings->statvis; + const float min = statvis->sharp_min; + const float max = statvis->sharp_max; + const float minmax_irange = 1.0f / (max - min); + + /* Can we avoid this extra allocation? */ + float *vert_angles = (float *)MEM_mallocN(sizeof(float) * mr->vert_len, __func__); + copy_vn_fl(vert_angles, mr->vert_len, -M_PI); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMesh *bm = em->bm; + BMFace *efa; + BMEdge *e; + /* first assign float values to verts */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + float angle = BM_edge_calc_face_angle_signed(e); + float *col1 = &vert_angles[BM_elem_index_get(e->v1)]; + float *col2 = &vert_angles[BM_elem_index_get(e->v2)]; + *col1 = max_ff(*col1, angle); + *col2 = max_ff(*col2, angle); + } + /* Copy vert value to loops. */ + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + int l_index = BM_elem_index_get(l_iter); + int v_index = BM_elem_index_get(l_iter->v); + r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange); + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + /* first assign float values to verts */ + const MPoly *mp = mr->mpoly; + + EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len); + + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + for (int i = 0; i < mp->totloop; i++) { + const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop]; + const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop]; + const MVert *v_curr = &mr->mvert[l_curr->v]; + const MVert *v_next = &mr->mvert[l_next->v]; + float angle; + void **pval; + bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval); + if (!value_is_init) { + *pval = mr->poly_normals[mp_index]; + /* non-manifold edge, yet... */ + continue; + } + if (*pval != nullptr) { + const float *f1_no = mr->poly_normals[mp_index]; + const float *f2_no = static_cast<const float *>(*pval); + angle = angle_normalized_v3v3(f1_no, f2_no); + angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle; + /* Tag as manifold. */ + *pval = nullptr; + } + else { + /* non-manifold edge */ + angle = DEG2RADF(90.0f); + } + float *col1 = &vert_angles[l_curr->v]; + float *col2 = &vert_angles[l_next->v]; + *col1 = max_ff(*col1, angle); + *col2 = max_ff(*col2, angle); + } + } + /* Remaining non manifold edges. */ + EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh); + for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) { + if (BLI_edgehashIterator_getValue(ehi) != nullptr) { + uint v1, v2; + const float angle = DEG2RADF(90.0f); + BLI_edgehashIterator_getKey(ehi, &v1, &v2); + float *col1 = &vert_angles[v1]; + float *col2 = &vert_angles[v2]; + *col1 = max_ff(*col1, angle); + *col2 = max_ff(*col2, angle); + } + } + BLI_edgehashIterator_free(ehi); + BLI_edgehash_free(eh, nullptr); + + const MLoop *ml = mr->mloop; + for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) { + r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange); + } + } + + MEM_freeN(vert_angles); +} + +static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + BLI_assert(mr->edit_bmesh); + + float *l_weight = (float *)GPU_vertbuf_get_data(vbo); + + switch (mr->toolsettings->statvis.type) { + case SCE_STATVIS_OVERHANG: + statvis_calc_overhang(mr, l_weight); + break; + case SCE_STATVIS_THICKNESS: + statvis_calc_thickness(mr, l_weight); + break; + case SCE_STATVIS_INTERSECT: + statvis_calc_intersect(mr, l_weight); + break; + case SCE_STATVIS_DISTORT: + statvis_calc_distort(mr, l_weight); + break; + case SCE_STATVIS_SHARP: + statvis_calc_sharp(mr, l_weight); + break; + } +} + +constexpr MeshExtract create_extractor_mesh_analysis() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_mesh_analysis_init; + extractor.finish = extract_analysis_iter_finish_mesh; + /* This is not needed for all visualization types. + * Maybe split into different extract. */ + extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.mesh_analysis); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc new file mode 100644 index 00000000000..933cf698368 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc @@ -0,0 +1,115 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Orco + * \{ */ + +typedef struct MeshExtract_Orco_Data { + float (*vbo_data)[4]; + float (*orco)[3]; +} MeshExtract_Orco_Data; + +static void extract_orco_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex + * attributes. This is a substantial waste of video-ram and should be done another way. + * Unfortunately, at the time of writing, I did not found any other "non disruptive" + * alternative. */ + GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + CustomData *cd_vdata = &mr->me->vdata; + + MeshExtract_Orco_Data *data = static_cast<MeshExtract_Orco_Data *>(tls_data); + data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo); + data->orco = static_cast<float(*)[3]>(CustomData_get_layer(cd_vdata, CD_ORCO)); + /* Make sure `orco` layer was requested only if needed! */ + BLI_assert(data->orco); +} + +static void extract_orco_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int UNUSED(f_index), + void *data) +{ + MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + float *loop_orco = orco_data->vbo_data[l_index]; + copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(l_iter->v)]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *data) +{ + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data; + float *loop_orco = orco_data->vbo_data[ml_index]; + copy_v3_v3(loop_orco, orco_data->orco[ml->v]); + loop_orco[3] = 0.0; /* Tag as not a generic attribute. */ + } +} + +constexpr MeshExtract create_extractor_orco() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_orco_init; + extractor.iter_poly_bm = extract_orco_iter_poly_bm; + extractor.iter_poly_mesh = extract_orco_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_Orco_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.orco); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_orco = blender::draw::create_extractor_orco(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc new file mode 100644 index 00000000000..01212935b87 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -0,0 +1,415 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Position and Vertex Normal + * \{ */ + +typedef struct PosNorLoop { + float pos[3]; + GPUPackedNormal nor; +} PosNorLoop; + +typedef struct MeshExtract_PosNor_Data { + PosNorLoop *vbo_data; + GPUNormal *normals; +} MeshExtract_PosNor_Data; + +static void extract_pos_nor_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* WARNING Adjust #PosNorLoop struct accordingly. */ + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_alias_add(&format, "vnor"); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); + + /* Pack normals per vert, reduce amount of computation. */ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(tls_data); + data->vbo_data = static_cast<PosNorLoop *>(GPU_vertbuf_get_data(vbo)); + data->normals = (GPUNormal *)MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__); + + /* Quicker than doing it for each loop. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMVert *eve; + int v; + BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { + data->normals[v].low = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve)); + } + } + else { + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + data->normals[v].low = GPU_normal_convert_i10_s3(mv->no); + } + } +} + +static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); + vert->nor = data->normals[BM_elem_index_get(l_iter->v)].low; + vert->nor.w = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + + PosNorLoop *vert = &data->vbo_data[ml_index]; + const MVert *mv = &mr->mvert[ml->v]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->normals[ml->v].low; + /* Flag for paint mode overlay. */ + if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && + (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + vert->nor.w = -1; + } + else if (mv->flag & SELECT) { + vert->nor.w = 1; + } + else { + vert->nor.w = 0; + } + } +} + +static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *eed, + const int ledge_index, + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + + int l_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low; + vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low; +} + +static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *med, + const int ledge_index, + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + vert[0].nor = data->normals[med->v1].low; + vert[1].nor = data->normals[med->v2].low; +} + +static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, + const BMVert *eve, + const int lvert_index, + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + const int l_index = offset + lvert_index; + PosNorLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + vert->nor = data->normals[BM_elem_index_get(eve)].low; +} + +static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, + const MVert *mv, + const int lvert_index, + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + vert->nor = data->normals[v_index].low; +} + +static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *_data) +{ + MeshExtract_PosNor_Data *data = static_cast<MeshExtract_PosNor_Data *>(_data); + MEM_freeN(data->normals); +} + +constexpr MeshExtract create_extractor_pos_nor() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_pos_nor_init; + extractor.iter_poly_bm = extract_pos_nor_iter_poly_bm; + extractor.iter_poly_mesh = extract_pos_nor_iter_poly_mesh; + extractor.iter_ledge_bm = extract_pos_nor_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh; + extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm; + extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh; + extractor.finish = extract_pos_nor_finish; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_PosNor_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor); + return extractor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract Position and High Quality Vertex Normal + * \{ */ + +typedef struct PosNorHQLoop { + float pos[3]; + short nor[4]; +} PosNorHQLoop; + +typedef struct MeshExtract_PosNorHQ_Data { + PosNorHQLoop *vbo_data; + GPUNormal *normals; +} MeshExtract_PosNorHQ_Data; + +static void extract_pos_nor_hq_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* WARNING Adjust #PosNorHQLoop struct accordingly. */ + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_alias_add(&format, "vnor"); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); + + /* Pack normals per vert, reduce amount of computation. */ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(tls_data); + data->vbo_data = static_cast<PosNorHQLoop *>(GPU_vertbuf_get_data(vbo)); + data->normals = (GPUNormal *)MEM_mallocN(sizeof(GPUNormal) * mr->vert_len, __func__); + + /* Quicker than doing it for each loop. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMVert *eve; + int v; + BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) { + normal_float_to_short_v3(data->normals[v].high, bm_vert_no_get(mr, eve)); + } + } + else { + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + copy_v3_v3_short(data->normals[v].high, mv->no); + } + } +} + +static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr, + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + PosNorHQLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, l_iter->v)); + copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l_iter->v)].high); + + vert->nor[3] = BM_elem_flag_test(f, BM_ELEM_HIDDEN) ? -1 : 0; + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + + PosNorHQLoop *vert = &data->vbo_data[ml_index]; + const MVert *mv = &mr->mvert[ml->v]; + copy_v3_v3(vert->pos, mv->co); + copy_v3_v3_short(vert->nor, data->normals[ml->v].high); + + /* Flag for paint mode overlay. */ + if (mp->flag & ME_HIDE || mv->flag & ME_HIDE || + ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) && + (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) { + vert->nor[3] = -1; + } + else if (mv->flag & SELECT) { + vert->nor[3] = 1; + } + else { + vert->nor[3] = 0; + } + } +} + +static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *eed, + const int ledge_index, + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + int l_index = mr->loop_len + ledge_index * 2; + PosNorHQLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1)); + copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2)); + copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high); + vert[0].nor[3] = 0; + copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high); + vert[1].nor[3] = 0; +} + +static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *med, + const int ledge_index, + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + const int ml_index = mr->loop_len + ledge_index * 2; + PosNorHQLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co); + copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co); + copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high); + vert[0].nor[3] = 0; + copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high); + vert[1].nor[3] = 0; +} + +static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr, + const BMVert *eve, + const int lvert_index, + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + const int l_index = offset + lvert_index; + PosNorHQLoop *vert = &data->vbo_data[l_index]; + copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve)); + copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high); + vert->nor[3] = 0; +} + +static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr, + const MVert *mv, + const int lvert_index, + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + const int ml_index = offset + lvert_index; + const int v_index = mr->lverts[lvert_index]; + PosNorHQLoop *vert = &data->vbo_data[ml_index]; + copy_v3_v3(vert->pos, mv->co); + copy_v3_v3_short(vert->nor, data->normals[v_index].high); + vert->nor[3] = 0; +} + +static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *_data) +{ + MeshExtract_PosNorHQ_Data *data = static_cast<MeshExtract_PosNorHQ_Data *>(_data); + MEM_freeN(data->normals); +} + +constexpr MeshExtract create_extractor_pos_nor_hq() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_pos_nor_hq_init; + extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm; + extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh; + extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_pos_nor_hq_iter_ledge_mesh; + extractor.iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm; + extractor.iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh; + extractor.finish = extract_pos_nor_hq_finish; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_PosNorHQ_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.pos_nor); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor(); +const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc new file mode 100644 index 00000000000..27bc94b0d85 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -0,0 +1,141 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_string.h" + +#include "BKE_paint.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Sculpt Data + * \{ */ + +static void extract_sculpt_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; + CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata; + + float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); + int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); + + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + typedef struct gpuSculptData { + uint8_t face_set_color[4]; + float mask; + } gpuSculptData; + + gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo); + MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK); + int cd_face_set_ofs = CustomData_get_offset(cd_pdata, CD_SCULPT_FACE_SETS); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + float v_mask = 0.0f; + if (cd_mask) { + v_mask = BM_ELEM_CD_GET_FLOAT(l_iter->v, cd_mask_ofs); + } + vbo_data->mask = v_mask; + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + if (cd_face_set) { + const int face_set_id = BM_ELEM_CD_GET_INT(l_iter->f, cd_face_set_ofs); + if (face_set_id != mr->me->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + face_set_id, mr->me->face_sets_color_seed, face_set_color); + } + } + copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color); + vbo_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + int mp_loop = 0; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + const MPoly *p = &mr->mpoly[mp_index]; + for (int l = 0; l < p->totloop; l++) { + float v_mask = 0.0f; + if (cd_mask) { + v_mask = cd_mask[loops[mp_loop].v]; + } + vbo_data->mask = v_mask; + + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + if (cd_face_set) { + const int face_set_id = cd_face_set[mp_index]; + /* Skip for the default color Face Set to render it white. */ + if (face_set_id != mr->me->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + face_set_id, mr->me->face_sets_color_seed, face_set_color); + } + } + copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color); + mp_loop++; + vbo_data++; + } + } + } +} + +constexpr MeshExtract create_extractor_sculpt_data() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_sculpt_data_init; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.sculpt_data); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc new file mode 100644 index 00000000000..22ba80b2769 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -0,0 +1,295 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Selection Index + * \{ */ + +static void extract_select_idx_init_impl(const MeshRenderData *mr, + const int len, + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* TODO rename "color" to something more descriptive. */ + GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, len); + *(uint32_t **)tls_data = (uint32_t *)GPU_vertbuf_get_data(vbo); +} + +static void extract_select_idx_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + extract_select_idx_init_impl(mr, mr->loop_len + mr->loop_loose_len, buf, tls_data); +} + +/* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the + * select element associated with this loop ID. This would remove the need for this separate + * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the + * shader to output original index. */ + +static void extract_poly_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int f_index, + void *data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + (*(uint32_t **)data)[l_index] = f_index; + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edge_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int UNUSED(f_index), + void *data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->e); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_vert_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int UNUSED(f_index), + void *data) +{ + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + (*(uint32_t **)data)[l_index] = BM_elem_index_get(l_iter->v); + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *eed, + const int ledge_index, + void *data) +{ + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed); + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed); +} + +static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, + const BMEdge *eed, + const int ledge_index, + void *data) +{ + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1); + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2); +} + +static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, + const BMVert *eve, + const int lvert_index, + void *data) +{ + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + (*(uint32_t **)data)[offset + lvert_index] = BM_elem_index_get(eve); +} + +static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int mp_index, + void *data) +{ + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + (*(uint32_t **)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index; + } +} + +static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *data) +{ + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + (*(uint32_t **)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e; + } +} + +static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *data) +{ + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + (*(uint32_t **)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v; + } +} + +static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *UNUSED(med), + const int ledge_index, + void *data) +{ + const int e_index = mr->ledges[ledge_index]; + const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index; + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig; + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig; +} + +static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, + const MEdge *med, + const int ledge_index, + void *data) +{ + int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1; + int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2; + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig; + (*(uint32_t **)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig; +} + +static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, + const MVert *UNUSED(mv), + const int lvert_index, + void *data) +{ + const int offset = mr->loop_len + (mr->edge_loose_len * 2); + + const int v_index = mr->lverts[lvert_index]; + const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index; + (*(uint32_t **)data)[offset + lvert_index] = v_orig; +} + +constexpr MeshExtract create_extractor_poly_idx() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_select_idx_init; + extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm; + extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(uint32_t *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.poly_idx); + return extractor; +} + +constexpr MeshExtract create_extractor_edge_idx() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_select_idx_init; + extractor.iter_poly_bm = extract_edge_idx_iter_poly_bm; + extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh; + extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(uint32_t *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.edge_idx); + return extractor; +} + +constexpr MeshExtract create_extractor_vert_idx() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_select_idx_init; + extractor.iter_poly_bm = extract_vert_idx_iter_poly_bm; + extractor.iter_poly_mesh = extract_vert_idx_iter_poly_mesh; + extractor.iter_ledge_bm = extract_vert_idx_iter_ledge_bm; + extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh; + extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm; + extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(uint32_t *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vert_idx); + return extractor; +} + +static void extract_fdot_idx_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + extract_select_idx_init_impl(mr, mr->poly_len, buf, tls_data); +} + +static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *UNUSED(f), + const int f_index, + void *data) +{ + (*(uint32_t **)data)[f_index] = f_index; +} + +static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *UNUSED(mp), + const int mp_index, + void *data) +{ + if (mr->p_origindex != nullptr) { + (*(uint32_t **)data)[mp_index] = mr->p_origindex[mp_index]; + } + else { + (*(uint32_t **)data)[mp_index] = mp_index; + } +} + +constexpr MeshExtract create_extractor_fdot_idx() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_fdot_idx_init; + extractor.iter_poly_bm = extract_fdot_idx_iter_poly_bm; + extractor.iter_poly_mesh = extract_fdot_idx_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(uint32_t *); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.fdot_idx); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx(); +const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx(); +const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx(); +const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc new file mode 100644 index 00000000000..3a3006f3f32 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc @@ -0,0 +1,93 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Skin Modifier Roots + * \{ */ + +typedef struct SkinRootData { + float size; + float local_pos[3]; +} SkinRootData; + +static void extract_skin_roots_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + /* Exclusively for edit mode. */ + BLI_assert(mr->bm); + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "local_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->bm->totvert); + + SkinRootData *vbo_data = (SkinRootData *)GPU_vertbuf_get_data(vbo); + + int root_len = 0; + int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN); + + BMIter iter; + BMVert *eve; + BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) { + const MVertSkin *vs = (const MVertSkin *)BM_ELEM_CD_GET_VOID_P(eve, cd_ofs); + if (vs->flag & MVERT_SKIN_ROOT) { + vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f; + copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve)); + vbo_data++; + root_len++; + } + } + + /* It's really unlikely that all verts will be roots. Resize to avoid losing VRAM. */ + GPU_vertbuf_data_len_set(vbo, root_len); +} + +constexpr MeshExtract create_extractor_skin_roots() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_skin_roots_init; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.skin_roots); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc new file mode 100644 index 00000000000..f251141c442 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -0,0 +1,266 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_string.h" + +#include "BKE_editmesh.h" +#include "BKE_editmesh_tangent.h" +#include "BKE_mesh.h" +#include "BKE_mesh_tangent.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Tangent layers + * \{ */ + +static void extract_tan_ex_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + GPUVertBuf *vbo, + const bool do_hq) +{ + GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10; + GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT; + + GPUVertFormat format = {0}; + GPU_vertformat_deinterleave(&format); + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; + uint32_t tan_layers = cache->cd_used.tan; + float(*orco)[3] = (float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO); + bool orco_allocated = false; + const bool use_orco_tan = cache->cd_used.tan_orco != 0; + + int tan_len = 0; + char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME]; + + for (int i = 0; i < MAX_MTFACE; i++) { + if (tan_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + /* Tangent layer name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode); + /* Active render layer name. */ + if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { + GPU_vertformat_alias_add(&format, "t"); + } + /* Active display layer name. */ + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { + GPU_vertformat_alias_add(&format, "at"); + } + + BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME); + } + } + if (use_orco_tan && orco == nullptr) { + /* If `orco` is not available compute it ourselves */ + orco_allocated = true; + orco = (float(*)[3])MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMesh *bm = mr->bm; + for (int v = 0; v < mr->vert_len; v++) { + const BMVert *eve = BM_vert_at_index(bm, v); + /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords. + * not the distorted ones. */ + copy_v3_v3(orco[v], eve->co); + } + } + else { + const MVert *mv = mr->mvert; + for (int v = 0; v < mr->vert_len; v++, mv++) { + copy_v3_v3(orco[v], mv->co); + } + } + BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0); + } + + /* Start Fresh */ + CustomData loop_data; + CustomData_reset(&loop_data); + if (tan_len != 0 || use_orco_tan) { + short tangent_mask = 0; + bool calc_active_tangent = false; + if (mr->extract_type == MR_EXTRACT_BMESH) { + BKE_editmesh_loop_tangent_calc(mr->edit_bmesh, + calc_active_tangent, + tangent_names, + tan_len, + mr->poly_normals, + mr->loop_normals, + orco, + &loop_data, + mr->loop_len, + &tangent_mask); + } + else { + BKE_mesh_calc_loop_tangent_ex(mr->mvert, + mr->mpoly, + mr->poly_len, + mr->mloop, + mr->mlooptri, + mr->tri_len, + cd_ldata, + calc_active_tangent, + tangent_names, + tan_len, + mr->poly_normals, + mr->loop_normals, + orco, + &loop_data, + mr->loop_len, + &tangent_mask); + } + } + + if (use_orco_tan) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(&loop_data, CD_TANGENT, 0); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode); + GPU_vertformat_alias_add(&format, "t"); + GPU_vertformat_alias_add(&format, "at"); + } + + if (orco_allocated) { + MEM_SAFE_FREE(orco); + } + + int v_len = mr->loop_len; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + /* VBO will not be used, only allocate minimum of memory. */ + v_len = 1; + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, v_len); + + if (do_hq) { + short(*tan_data)[4] = (short(*)[4])GPU_vertbuf_get_data(vbo); + for (int i = 0; i < tan_len; i++) { + const char *name = tangent_names[i]; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( + &loop_data, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + tan_data++; + } + } + if (use_orco_tan) { + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + normal_float_to_short_v3(*tan_data, layer_data[ml_index]); + (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN; + tan_data++; + } + } + } + else { + GPUPackedNormal *tan_data = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo); + for (int i = 0; i < tan_len; i++) { + const char *name = tangent_names[i]; + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named( + &loop_data, CD_TANGENT, name); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; + tan_data++; + } + } + if (use_orco_tan) { + float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) { + *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]); + tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2; + tan_data++; + } + } + } + + CustomData_free(&loop_data, mr->loop_len); +} + +static void extract_tan_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + extract_tan_ex_init(mr, cache, vbo, false); +} + +constexpr MeshExtract create_extractor_tan() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_tan_init; + extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan); + return extractor; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract HQ Tangent layers + * \{ */ + +static void extract_tan_hq_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + extract_tan_ex_init(mr, cache, vbo, true); +} + +constexpr MeshExtract create_extractor_tan_hq() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_tan_hq_init; + extractor.data_type = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.tan); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_tan = blender::draw::create_extractor_tan(); +const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc new file mode 100644 index 00000000000..0f3c2483296 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -0,0 +1,136 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "BLI_string.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract UV layers + * \{ */ + +static void extract_uv_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + GPU_vertformat_deinterleave(&format); + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + uint32_t uv_layers = cache->cd_used.uv; + /* HACK to fix T68857 */ + if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + uv_layers |= (1 << layer); + } + } + + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i); + + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + /* UV layer name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + /* Auto layer name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(&format, attr_name); + /* Active render layer name. */ + if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { + GPU_vertformat_alias_add(&format, "u"); + } + /* Active display layer name. */ + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { + GPU_vertformat_alias_add(&format, "au"); + /* Alias to `pos` for edit uvs. */ + GPU_vertformat_alias_add(&format, "pos"); + } + /* Stencil mask uv layer name. */ + if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) { + GPU_vertformat_alias_add(&format, "mu"); + } + } + } + + int v_len = mr->loop_len; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + /* VBO will not be used, only allocate minimum of memory. */ + v_len = 1; + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, v_len); + + float(*uv_data)[2] = (float(*)[2])GPU_vertbuf_get_data(vbo); + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); + memcpy(uv_data, luv->uv, sizeof(*uv_data)); + uv_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + MLoopUV *layer_data = (MLoopUV *)CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) { + memcpy(uv_data, layer_data->uv, sizeof(*uv_data)); + } + } + } + } +} + +constexpr MeshExtract create_extractor_uv() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_uv_init; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.uv); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_uv = blender::draw::create_extractor_uv(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc new file mode 100644 index 00000000000..1bbe8b6f859 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -0,0 +1,191 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_string.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract VCol + * \{ */ + +static void extract_vcol_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + GPU_vertformat_deinterleave(&format); + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; + uint32_t vcol_layers = cache->cd_used.vcol; + uint32_t svcol_layers = cache->cd_used.sculpt_vcol; + + for (int i = 0; i < MAX_MCOL; i++) { + if (vcol_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + + BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { + GPU_vertformat_alias_add(&format, "ac"); + } + + /* Gather number of auto layers. */ + /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 && + CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) { + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(&format, attr_name); + } + } + } + + /* Sculpt Vertex Colors */ + if (U.experimental.use_sculpt_vertex_colors) { + for (int i = 0; i < 8; i++) { + if (svcol_layers & (1 << i)) { + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + + BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); + GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "ac"); + } + /* Gather number of auto layers. */ + /* We only do `vcols` that are not overridden by `uvs`. */ + if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + GPU_vertformat_alias_add(&format, attr_name); + } + } + } + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + + typedef struct gpuMeshVcol { + ushort r, g, b, a; + } gpuMeshVcol; + + gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); + MLoop *loops = (MLoop *)CustomData_get_layer(cd_ldata, CD_MLOOP); + + for (int i = 0; i < MAX_MCOL; i++) { + if (vcol_layers & (1 << i)) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + vcol_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + } + } + } + + if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) { + if (mr->extract_type == MR_EXTRACT_BMESH) { + int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i); + BMIter f_iter; + BMFace *efa; + BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const MPropCol *prop_col = (const MPropCol *)BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs); + vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]); + vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]); + vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]); + vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]); + vcol_data++; + } while ((l_iter = l_iter->next) != l_first); + } + } + else { + MPropCol *vcol = (MPropCol *)CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i); + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) { + vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]); + vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]); + vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]); + vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]); + } + } + } + } +} + +constexpr MeshExtract create_extractor_vcol() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_vcol_init; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.vcol); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_vcol = blender::draw::create_extractor_vcol(); +} diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc new file mode 100644 index 00000000000..7a285434a66 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -0,0 +1,189 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "MEM_guardedalloc.h" + +#include "BKE_deform.h" + +#include "draw_cache_extract_mesh_private.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Vertex Weight + * \{ */ + +typedef struct MeshExtract_Weight_Data { + float *vbo_data; + const DRW_MeshWeightState *wstate; + const MDeformVert *dvert; /* For #Mesh. */ + int cd_ofs; /* For #BMesh. */ +} MeshExtract_Weight_Data; + +static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate) +{ + /* Error state. */ + if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) { + return -2.0f; + } + if (dvert == nullptr) { + return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f; + } + + float input = 0.0f; + if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) { + /* Multi-Paint feature */ + bool is_normalized = (wstate->flags & (DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE | + DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE)); + input = BKE_defvert_multipaint_collective_weight(dvert, + wstate->defgroup_len, + wstate->defgroup_sel, + wstate->defgroup_sel_count, + is_normalized); + /* make it black if the selected groups have no weight on a vertex */ + if (input == 0.0f) { + return -1.0f; + } + } + else { + /* default, non tricky behavior */ + input = BKE_defvert_find_weight(dvert, wstate->defgroup_active); + + if (input == 0.0f) { + switch (wstate->alert_mode) { + case OB_DRAW_GROUPUSER_ACTIVE: + return -1.0f; + break; + case OB_DRAW_GROUPUSER_ALL: + if (BKE_defvert_is_weight_zero(dvert, wstate->defgroup_len)) { + return -1.0f; + } + break; + } + } + } + + /* Lock-Relative: display the fraction of current weight vs total unlocked weight. */ + if (wstate->flags & DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE) { + input = BKE_defvert_lock_relative_weight( + input, dvert, wstate->defgroup_len, wstate->defgroup_locked, wstate->defgroup_unlocked); + } + + CLAMP(input, 0.0f, 1.0f); + return input; +} + +static void extract_weights_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); + + MeshExtract_Weight_Data *data = static_cast<MeshExtract_Weight_Data *>(tls_data); + data->vbo_data = (float *)GPU_vertbuf_get_data(vbo); + data->wstate = &cache->weight_state; + + if (data->wstate->defgroup_active == -1) { + /* Nothing to show. */ + data->dvert = nullptr; + data->cd_ofs = -1; + } + else if (mr->extract_type == MR_EXTRACT_BMESH) { + data->dvert = nullptr; + data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT); + } + else { + data->dvert = (const MDeformVert *)CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT); + data->cd_ofs = -1; + } +} + +static void extract_weights_iter_poly_bm(const MeshRenderData *UNUSED(mr), + const BMFace *f, + const int UNUSED(f_index), + void *_data) +{ + MeshExtract_Weight_Data *data = static_cast<MeshExtract_Weight_Data *>(_data); + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + const int l_index = BM_elem_index_get(l_iter); + if (data->cd_ofs != -1) { + const MDeformVert *dvert = (const MDeformVert *)BM_ELEM_CD_GET_VOID_P(l_iter->v, + data->cd_ofs); + data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate); + } + else { + data->vbo_data[l_index] = evaluate_vertex_weight(nullptr, data->wstate); + } + } while ((l_iter = l_iter->next) != l_first); +} + +static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, + const MPoly *mp, + const int UNUSED(mp_index), + void *_data) +{ + MeshExtract_Weight_Data *data = static_cast<MeshExtract_Weight_Data *>(_data); + const MLoop *mloop = mr->mloop; + const int ml_index_end = mp->loopstart + mp->totloop; + for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) { + const MLoop *ml = &mloop[ml_index]; + if (data->dvert != nullptr) { + const MDeformVert *dvert = &data->dvert[ml->v]; + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + else { + const MDeformVert *dvert = nullptr; + data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate); + } + } +} + +constexpr MeshExtract create_extractor_weights() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_weights_init; + extractor.iter_poly_bm = extract_weights_iter_poly_bm; + extractor.iter_poly_mesh = extract_weights_iter_poly_mesh; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = sizeof(MeshExtract_Weight_Data); + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, vbo.weights); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_weights = blender::draw::create_extractor_weights(); +} |