diff options
Diffstat (limited to 'source/blender/draw/intern/mesh_extractors')
25 files changed, 2017 insertions, 194 deletions
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index d9f397fd8b8..37eb4f80442 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -39,6 +39,8 @@ extern "C" { #endif +struct DRWSubdivCache; + #define MIN_RANGE_LEN 1024 /* ---------------------------------------------------------------------- */ @@ -82,7 +84,8 @@ typedef struct MeshRenderData { const float (*bm_poly_centers)[3]; int *v_origindex, *e_origindex, *p_origindex; - int crease_ofs; + int edge_crease_ofs; + int vert_crease_ofs; int bweight_ofs; int freestyle_edge_ofs; int freestyle_face_ofs; @@ -98,8 +101,9 @@ typedef struct MeshRenderData { BMFace *efa_act_uv; /* Data created on-demand (usually not for #BMesh based data). */ MLoopTri *mlooptri; + const float (*vert_normals)[3]; + const float (*poly_normals)[3]; float (*loop_normals)[3]; - float (*poly_normals)[3]; int *lverts, *ledges; struct { @@ -168,39 +172,43 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e /* ---------------------------------------------------------------------- */ /** \name Mesh Elements Extract Struct * \{ */ + /* TODO(jbakker): move parameters inside a struct. */ -typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, - BMLoop **elt, - const int elt_index, - void *data); + +typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data); typedef void(ExtractTriMeshFn)(const MeshRenderData *mr, const MLoopTri *mlt, - const int elt_index, + int elt_index, void *data); typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr, const BMFace *f, - const int f_index, + int f_index, void *data); typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr, const MPoly *mp, - const int mp_index, + int mp_index, void *data); typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr, const BMEdge *eed, - const int ledge_index, + int ledge_index, void *data); typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr, const MEdge *med, - const int ledge_index, + int ledge_index, void *data); typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr, const BMVert *eve, - const int lvert_index, + int lvert_index, void *data); typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, const MVert *mv, - const int lvert_index, + int lvert_index, void *data); +typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *data); typedef void(ExtractInitFn)(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer, @@ -211,6 +219,27 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *data); typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata); +typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); +typedef void(ExtractIterSubdivBMeshFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data, + uint subdiv_quad_index, + const BMFace *coarse_quad); +typedef void(ExtractIterSubdivMeshFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data, + uint subdiv_quad_index, + const MPoly *coarse_quad); +typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); + typedef struct MeshExtract { /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; @@ -223,9 +252,15 @@ typedef struct MeshExtract { ExtractLEdgeMeshFn *iter_ledge_mesh; ExtractLVertBMeshFn *iter_lvert_bm; ExtractLVertMeshFn *iter_lvert_mesh; + ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv; /** Executed on one worker thread after all elements iterations. */ ExtractTaskReduceFn *task_reduce; ExtractFinishFn *finish; + /** Executed on main thread for subdivision evaluation. */ + ExtractInitSubdivFn *init_subdiv; + ExtractIterSubdivBMeshFn *iter_subdiv_bm; + ExtractIterSubdivMeshFn *iter_subdiv_mesh; + ExtractFinishSubdivFn *finish_subdiv; /** Used to request common data. */ eMRDataType data_type; size_t data_size; @@ -241,31 +276,42 @@ typedef struct MeshExtract { /** \} */ /* draw_cache_extract_mesh_render_data.c */ -MeshRenderData *mesh_render_data_create(Mesh *me, - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, + +/** + * \param is_mode_active: When true, use the modifiers from the edit-data, + * otherwise don't use modifiers as they are not from this object. + */ +MeshRenderData *mesh_render_data_create(Object *object, + Mesh *me, + bool is_editmode, + bool is_paint_mode, + bool is_mode_active, const float obmat[4][4], - const bool do_final, - const bool do_uvedit, + bool do_final, + bool do_uvedit, const ToolSettings *ts); void mesh_render_data_free(MeshRenderData *mr); -void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag); +void mesh_render_data_update_normals(MeshRenderData *mr, eMRDataType data_flag); void mesh_render_data_update_loose_geom(MeshRenderData *mr, MeshBufferCache *cache, - const eMRIterType iter_type, - const eMRDataType data_flag); + eMRIterType iter_type, + eMRDataType data_flag); void mesh_render_data_update_polys_sorted(MeshRenderData *mr, MeshBufferCache *cache, - const eMRDataType data_flag); + eMRDataType data_flag); +/** + * Part of the creation of the #MeshRenderData that happens in a thread. + */ void mesh_render_data_update_looptris(MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType data_flag); + eMRIterType iter_type, + eMRDataType data_flag); /* draw_cache_extract_mesh_extractors.c */ typedef struct EditLoopData { uchar v_flag; uchar e_flag; + /* This is used for both vertex and edge creases. The edge crease value is stored in the bottom 4 + * bits, while the vertex crease is stored in the upper 4 bits. */ uchar crease; uchar bweight; } EditLoopData; @@ -273,19 +319,19 @@ typedef struct EditLoopData { void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist); 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); + bool do_hq_normals, + bool do_single_mat); void mesh_render_data_face_flag(const MeshRenderData *mr, const BMFace *efa, - const int cd_ofs, + int cd_ofs, EditLoopData *eattr); void mesh_render_data_loop_flag(const MeshRenderData *mr, BMLoop *l, - const int cd_ofs, + int cd_ofs, EditLoopData *eattr); void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, BMLoop *l, - const int cd_ofs, + int cd_ofs, EditLoopData *eattr); extern const MeshExtract extract_tris; @@ -328,6 +374,7 @@ extern const MeshExtract extract_poly_idx; extern const MeshExtract extract_edge_idx; extern const MeshExtract extract_vert_idx; extern const MeshExtract extract_fdot_idx; +extern const MeshExtract extract_attr[GPU_MAX_ATTR]; #ifdef __cplusplus } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index d06fb91411e..cd71beb1f02 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Edit UV Triangles Indices @@ -94,6 +96,79 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init(&data->elb, + GPU_PRIM_TRIS, + subdiv_cache->num_subdiv_triangles, + subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_tris_iter_subdiv_bm(const DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + void *_data, + uint subdiv_quad_index, + const BMFace *coarse_quad) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + const uint loop_idx = subdiv_quad_index * 4; + + edituv_tri_add(data, + BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 1, + loop_idx + 2); + + edituv_tri_add(data, + BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 2, + loop_idx + 3); +} + +static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + void *_data, + uint subdiv_quad_index, + const MPoly *coarse_quad) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + const uint loop_idx = subdiv_quad_index * 4; + + edituv_tri_add(data, + (coarse_quad->flag & ME_HIDE) != 0, + (coarse_quad->flag & ME_FACE_SEL) != 0, + loop_idx, + loop_idx + 1, + loop_idx + 2); + + edituv_tri_add(data, + (coarse_quad->flag & ME_HIDE) != 0, + (coarse_quad->flag & ME_FACE_SEL) != 0, + loop_idx, + loop_idx + 2, + loop_idx + 3); +} + +static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_tris() { MeshExtract extractor = {nullptr}; @@ -101,6 +176,10 @@ constexpr MeshExtract create_extractor_edituv_tris() extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm; extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh; extractor.finish = extract_edituv_tris_finish; + extractor.init_subdiv = extract_edituv_tris_init_subdiv; + extractor.iter_subdiv_bm = extract_edituv_tris_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_edituv_tris_iter_subdiv_mesh; + extractor.finish_subdiv = extract_edituv_tris_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -184,6 +263,77 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_lines_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const BMFace *coarse_poly) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { + const int edge_origindex = subdiv_loop_edge_index[loop_idx]; + const bool real_edge = (edge_origindex != -1 && + (mr->e_origindex == nullptr || + mr->e_origindex[edge_origindex] != ORIGINDEX_NONE)); + edituv_edge_add(data, + BM_elem_flag_test_bool(coarse_poly, BM_ELEM_HIDDEN) != 0 || !real_edge, + BM_elem_flag_test_bool(coarse_poly, BM_ELEM_SELECT) != 0, + loop_idx, + (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); + } +} + +static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const MPoly *coarse_poly) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { + const int edge_origindex = subdiv_loop_edge_index[loop_idx]; + const bool real_edge = (edge_origindex != -1 && + (mr->e_origindex == nullptr || + mr->e_origindex[edge_origindex] != ORIGINDEX_NONE)); + edituv_edge_add(data, + (coarse_poly->flag & ME_HIDE) != 0 || !real_edge, + (coarse_poly->flag & ME_FACE_SEL) != 0, + loop_idx, + (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); + } +} + +static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_lines() { MeshExtract extractor = {nullptr}; @@ -191,6 +341,10 @@ constexpr MeshExtract create_extractor_edituv_lines() extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh; extractor.finish = extract_edituv_lines_finish; + extractor.init_subdiv = extract_edituv_lines_init_subdiv; + extractor.iter_subdiv_bm = extract_edituv_lines_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_edituv_lines_iter_subdiv_mesh; + extractor.finish_subdiv = extract_edituv_lines_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -268,6 +422,75 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const BMFace *coarse_quad) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint i = start_loop_idx; i < end_loop_idx; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + vert_origindex != -1 && + mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); + edituv_point_add(data, + (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert, + BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0, + i); + } +} + +static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const MPoly *coarse_quad) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint i = start_loop_idx; i < end_loop_idx; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + vert_origindex != -1 && + mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); + edituv_point_add(data, + ((coarse_quad->flag & ME_HIDE) != 0) || !real_vert, + (coarse_quad->flag & ME_FACE_SEL) != 0, + i); + } +} + +static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_points() { MeshExtract extractor = {nullptr}; @@ -275,6 +498,10 @@ constexpr MeshExtract create_extractor_edituv_points() extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh; extractor.finish = extract_edituv_points_finish; + extractor.init_subdiv = extract_edituv_points_init_subdiv; + extractor.iter_subdiv_bm = extract_edituv_points_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_edituv_points_iter_subdiv_mesh; + extractor.finish_subdiv = extract_edituv_points_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -388,5 +615,3 @@ const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_ const MeshExtract extract_edituv_points = blender::draw::create_extractor_edituv_points(); const MeshExtract extract_edituv_fdots = blender::draw::create_extractor_edituv_fdots(); } - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc index ea58e1aeed8..2e8b85250f3 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc @@ -110,10 +110,9 @@ constexpr MeshExtract create_extractor_fdots() } /** \} */ + } // namespace blender::draw extern "C" { const MeshExtract extract_fdots = blender::draw::create_extractor_fdots(); } - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 54f5611106f..3d9729dea56 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + GPU_indexbuf_init_build_on_device(ibo, + subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2); + + draw_subdiv_build_lines_buffer(subdiv_cache, ibo); +} + +static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len)); +} + constexpr MeshExtract create_extractor_lines() { MeshExtract extractor = {nullptr}; @@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines() extractor.iter_poly_mesh = extract_lines_iter_poly_mesh; extractor.iter_ledge_bm = extract_lines_iter_ledge_bm; extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh; + extractor.init_subdiv = extract_lines_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv; extractor.task_reduce = extract_lines_task_reduce; extractor.finish = extract_lines_finish; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index 522afcd44a1..2b01b6801c2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data { uint *vert_to_loop; }; +static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data, + uint vert_len, + uint loop_len, + uint tess_edge_len) +{ + data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__)); + + GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len); + data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); + data->is_manifold = true; +} + static void extract_lines_adjacency_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), @@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr, uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data); - data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__)); - - GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len); - data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); - data->is_manifold = true; + line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len); } BLI_INLINE void lines_adjacency_triangle( @@ -171,9 +180,72 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->vert_to_loop); } -#undef NO_EDGE +static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *_data) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); -/** \} */ + /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad + * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in + * total: (number_of_loops + number_of_quads). */ + const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads; + line_adjacency_data_init( + data, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops, tess_len); +} + +static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + void *_data, + uint subdiv_quad_index) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + + const uint loop_index = subdiv_quad_index * 4; + const uint l0 = loop_index + 0; + const uint l1 = loop_index + 1; + const uint l2 = loop_index + 2; + const uint l3 = loop_index + 3; + + const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0]; + const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1]; + const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2]; + const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3]; + + lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data); + lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data); +} + +static void extract_lines_adjacency_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const BMFace *UNUSED(coarse_quad)) +{ + extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index); +} + +static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const MPoly *UNUSED(coarse_quad)) +{ + extract_lines_adjacency_iter_subdiv(subdiv_cache, mr, _data, subdiv_quad_index); +} + +static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *_data) +{ + extract_lines_adjacency_finish(mr, cache, buf, _data); +} + +#undef NO_EDGE constexpr MeshExtract create_extractor_lines_adjacency() { @@ -182,6 +254,10 @@ constexpr MeshExtract create_extractor_lines_adjacency() extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm; extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh; extractor.finish = extract_lines_adjacency_finish; + extractor.init_subdiv = extract_lines_adjacency_init_subdiv; + extractor.iter_subdiv_bm = extract_lines_adjacency_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_lines_adjacency_iter_subdiv_mesh; + extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data); extractor.use_threading = false; @@ -189,10 +265,10 @@ constexpr MeshExtract create_extractor_lines_adjacency() return extractor; } +/** \} */ + } // namespace blender::draw extern "C" { const MeshExtract extract_lines_adjacency = blender::draw::create_extractor_lines_adjacency(); } - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc index 494a43e97d1..f7eb5022cdc 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc @@ -103,8 +103,6 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->select_map); } -/** \} */ - constexpr MeshExtract create_extractor_lines_paint_mask() { MeshExtract extractor = {nullptr}; @@ -118,10 +116,10 @@ constexpr MeshExtract create_extractor_lines_paint_mask() return extractor; } +/** \} */ + } // namespace blender::draw extern "C" { const MeshExtract extract_lines_paint_mask = blender::draw::create_extractor_lines_paint_mask(); } - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index b801ba04162..c3f89ab96ee 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -32,6 +33,7 @@ namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Point Indices * \{ */ + static void extract_points_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), @@ -154,6 +156,69 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buffer), + void *data) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + /* Copy the points as the data upload will free them. */ + elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices); + elb->index_len = mr->vert_len; + elb->index_min = 0; + elb->index_max = subdiv_cache->num_subdiv_loops + mr->loop_loose_len; + elb->prim_type = GPU_PRIM_POINTS; +} + +static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *data) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + if (elb->data[loose_edge->v1] == -1u) { + GPU_indexbuf_set_point_vert(elb, loose_edge->v1, offset); + } + if (elb->data[loose_edge->v2] == -1u) { + GPU_indexbuf_set_point_vert(elb, loose_edge->v2, offset + 1); + } + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + if (elb->data[loose_geom->verts[i]] == -1u) { + GPU_indexbuf_set_point_vert(elb, loose_geom->verts[i], offset); + } + offset += 1; + } +} + +static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *_userdata) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(elb, ibo); +} + constexpr MeshExtract create_extractor_points() { MeshExtract extractor = {nullptr}; @@ -166,6 +231,9 @@ constexpr MeshExtract create_extractor_points() extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh; extractor.task_reduce = extract_points_task_reduce; extractor.finish = extract_points_finish; + extractor.init_subdiv = extract_points_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv; + extractor.finish_subdiv = extract_points_finish_subdiv; extractor.use_threading = true; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); @@ -173,10 +241,10 @@ constexpr MeshExtract create_extractor_points() return extractor; } +/** \} */ + } // namespace blender::draw extern "C" { const MeshExtract extract_points = blender::draw::create_extractor_points(); } - -/** \} */ diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index 54e733d3d86..b1ace8bc6c9 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from) @@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr, } } +static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + /* Initialize the index buffer, it was already allocated, it will be filled on the device. */ + GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3); + + if (cache->tris_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + if (cache->tris_per_mat[i] == nullptr) { + cache->tris_per_mat[i] = GPU_indexbuf_calloc(); + } + + /* Multiply by 6 since we have 2 triangles per quad. */ + const int start = subdiv_cache->mat_start[i] * 6; + const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6; + GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len); + } + } + + draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len); +} + constexpr MeshExtract create_extractor_tris() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_poly_bm = extract_tris_iter_poly_bm; extractor.iter_poly_mesh = extract_tris_iter_poly_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; @@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_single_mat_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm; extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc new file mode 100644 index 00000000000..b846da3f016 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -0,0 +1,489 @@ +/* + * 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 <functional> + +#include "BLI_math_vec_types.hh" +#include "BLI_string.h" + +#include "BKE_attribute.h" + +#include "draw_subdivision.h" +#include "extract_mesh.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Attributes + * \{ */ + +static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain) +{ + switch (domain) { + default: { + return nullptr; + } + case ATTR_DOMAIN_POINT: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; + } + case ATTR_DOMAIN_CORNER: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + } + case ATTR_DOMAIN_FACE: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata; + } + case ATTR_DOMAIN_EDGE: { + return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata; + } + } +} + +/* Utility to convert from the type used in the attributes to the types for the VBO. + * This is mostly used to promote integers and booleans to floats, as other types (float, float2, + * etc.) directly map to available GPU types. Booleans are still converted as attributes are vec4 + * in the shader. + */ +template<typename AttributeType, typename VBOType> struct attribute_type_converter { + static VBOType convert_value(AttributeType value) + { + if constexpr (std::is_same_v<AttributeType, VBOType>) { + return value; + } + + /* This should only concern bools which are converted to floats. */ + return static_cast<VBOType>(value); + } +}; + +/* Similar to the one in #extract_mesh_vcol_vbo.cc */ +struct gpuMeshCol { + ushort r, g, b, a; +}; + +template<> struct attribute_type_converter<MPropCol, gpuMeshCol> { + static gpuMeshCol convert_value(MPropCol value) + { + gpuMeshCol result; + result.r = unit_float_to_ushort_clamp(value.color[0]); + result.g = unit_float_to_ushort_clamp(value.color[1]); + result.b = unit_float_to_ushort_clamp(value.color[2]); + result.a = unit_float_to_ushort_clamp(value.color[3]); + return result; + } +}; + +/* Return the number of component for the attribute's value type, or 0 if is it unsupported. */ +static uint gpu_component_size_for_attribute_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_BOOL: + case CD_PROP_INT32: + case CD_PROP_FLOAT: { + /* TODO(kevindietrich) : should be 1 when scalar attributes conversion is handled by us. See + * comment #extract_attr_init. */ + return 3; + } + case CD_PROP_FLOAT2: { + return 2; + } + case CD_PROP_FLOAT3: { + return 3; + } + case CD_PROP_COLOR: { + return 4; + } + default: { + return 0; + } + } +} + +static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_INT32: { + return GPU_FETCH_INT_TO_FLOAT; + } + case CD_PROP_COLOR: { + return GPU_FETCH_INT_TO_FLOAT_UNIT; + } + default: { + return GPU_FETCH_FLOAT; + } + } +} + +static GPUVertCompType get_comp_type_for_type(CustomDataType type) +{ + switch (type) { + case CD_PROP_INT32: { + return GPU_COMP_I32; + } + case CD_PROP_COLOR: { + return GPU_COMP_U16; + } + default: { + return GPU_COMP_F32; + } + } +} + +static void init_vbo_for_attribute(const MeshRenderData *mr, + GPUVertBuf *vbo, + const DRW_AttributeRequest &request, + bool build_on_device, + uint32_t len) +{ + GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type); + GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type); + const uint comp_size = gpu_component_size_for_attribute_type(request.cd_type); + /* We should not be here if the attribute type is not supported. */ + BLI_assert(comp_size != 0); + + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; + const char *layer_name = CustomData_get_layer_name( + custom_data, request.cd_type, request.layer_index); + GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); + /* Attributes use auto-name. */ + BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); + + GPUVertFormat format = {0}; + GPU_vertformat_deinterleave(&format); + GPU_vertformat_attr_add(&format, attr_name, comp_type, comp_size, fetch_mode); + + /* Ensure Sculpt Vertex Colors are properly aliased. */ + if (request.cd_type == CD_PROP_COLOR && request.domain == ATTR_DOMAIN_POINT) { + CustomData *cd_vdata = get_custom_data_for_domain(mr, ATTR_DOMAIN_POINT); + if (request.layer_index == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "c"); + } + if (request.layer_index == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) { + GPU_vertformat_alias_add(&format, "ac"); + } + } + + if (build_on_device) { + GPU_vertbuf_init_build_on_device(vbo, &format, len); + } + else { + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, len); + } +} + +template<typename AttributeType, typename VBOType> +static void fill_vertbuf_with_attribute(const MeshRenderData *mr, + VBOType *vbo_data, + const DRW_AttributeRequest &request) +{ + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + BLI_assert(custom_data); + const int layer_index = request.layer_index; + + const MPoly *mpoly = mr->mpoly; + const MLoop *mloop = mr->mloop; + + const AttributeType *attr_data = static_cast<AttributeType *>( + CustomData_get_layer_n(custom_data, request.cd_type, layer_index)); + + using converter = attribute_type_converter<AttributeType, VBOType>; + + switch (request.domain) { + default: { + BLI_assert(false); + break; + } + case ATTR_DOMAIN_POINT: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { + *vbo_data = converter::convert_value(attr_data[mloop->v]); + } + break; + } + case ATTR_DOMAIN_CORNER: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++) { + *vbo_data = converter::convert_value(attr_data[ml_index]); + } + break; + } + case ATTR_DOMAIN_EDGE: { + for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vbo_data++, mloop++) { + *vbo_data = converter::convert_value(attr_data[mloop->e]); + } + break; + } + case ATTR_DOMAIN_FACE: { + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) { + const MPoly &poly = mpoly[mp_index]; + const VBOType value = converter::convert_value(attr_data[mp_index]); + for (int l = 0; l < poly.totloop; l++) { + *vbo_data++ = value; + } + } + break; + } + } +} + +template<typename AttributeType, typename VBOType> +static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr, + VBOType *&vbo_data, + const DRW_AttributeRequest &request) +{ + const CustomData *custom_data = get_custom_data_for_domain(mr, request.domain); + BLI_assert(custom_data); + const int layer_index = request.layer_index; + + int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index); + + using converter = attribute_type_converter<AttributeType, VBOType>; + + 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 AttributeType *attr_data = nullptr; + if (request.domain == ATTR_DOMAIN_POINT) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_CORNER) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_FACE) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(efa, cd_ofs)); + } + else if (request.domain == ATTR_DOMAIN_EDGE) { + attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs)); + } + else { + BLI_assert(false); + continue; + } + *vbo_data = converter::convert_value(*attr_data); + vbo_data++; + } while ((l_iter = l_iter->next) != l_first); + } +} + +template<typename AttributeType, typename VBOType = AttributeType> +static void extract_attr_generic(const MeshRenderData *mr, + GPUVertBuf *vbo, + const DRW_AttributeRequest &request) +{ + VBOType *vbo_data = static_cast<VBOType *>(GPU_vertbuf_get_data(vbo)); + + if (mr->extract_type == MR_EXTRACT_BMESH) { + fill_vertbuf_with_attribute_bm<AttributeType>(mr, vbo_data, request); + } + else { + fill_vertbuf_with_attribute<AttributeType>(mr, vbo_data, request); + } +} + +static void extract_attr_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data), + int index) +{ + const DRW_MeshAttributes *attrs_used = &cache->attr_used; + const DRW_AttributeRequest &request = attrs_used->requests[index]; + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + + init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len)); + + /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by + * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the + * Blender convention, it should be `vec4(s, s, s, 1)`. This could be resolved using a similar + * texture as for volume attribute, so we can control the conversion ourselves. */ + switch (request.cd_type) { + case CD_PROP_BOOL: { + extract_attr_generic<bool, float3>(mr, vbo, request); + break; + } + case CD_PROP_INT32: { + extract_attr_generic<int32_t, float3>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT: { + extract_attr_generic<float, float3>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT2: { + extract_attr_generic<float2>(mr, vbo, request); + break; + } + case CD_PROP_FLOAT3: { + extract_attr_generic<float3>(mr, vbo, request); + break; + } + case CD_PROP_COLOR: { + extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request); + break; + } + default: { + BLI_assert(false); + } + } +} + +static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data), + int index) +{ + const DRW_MeshAttributes *attrs_used = &cache->attr_used; + const DRW_AttributeRequest &request = attrs_used->requests[index]; + + Mesh *coarse_mesh = subdiv_cache->mesh; + + const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type); + + /* Prepare VBO for coarse data. The compute shader only expects floats. */ + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + static GPUVertFormat coarse_format = {0}; + GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT); + GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC); + GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop)); + + switch (request.cd_type) { + case CD_PROP_BOOL: { + extract_attr_generic<bool, float3>(mr, src_data, request); + break; + } + case CD_PROP_INT32: { + extract_attr_generic<int32_t, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT: { + extract_attr_generic<float, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT2: { + extract_attr_generic<float2>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT3: { + extract_attr_generic<float3>(mr, src_data, request); + break; + } + case CD_PROP_COLOR: { + extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request); + break; + } + default: { + BLI_assert(false); + } + } + + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops); + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data( + subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0); + + GPU_vertbuf_discard(src_data); +} + +/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to + * extract. The overall API does not allow us to pass this in a convenient way. */ +#define EXTRACT_INIT_WRAPPER(index) \ + static void extract_attr_init##index( \ + const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \ + { \ + extract_attr_init(mr, cache, buf, tls_data, index); \ + } \ + static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \ + const MeshRenderData *mr, \ + struct MeshBatchCache *cache, \ + void *buf, \ + void *tls_data) \ + { \ + extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \ + } + +EXTRACT_INIT_WRAPPER(0) +EXTRACT_INIT_WRAPPER(1) +EXTRACT_INIT_WRAPPER(2) +EXTRACT_INIT_WRAPPER(3) +EXTRACT_INIT_WRAPPER(4) +EXTRACT_INIT_WRAPPER(5) +EXTRACT_INIT_WRAPPER(6) +EXTRACT_INIT_WRAPPER(7) +EXTRACT_INIT_WRAPPER(8) +EXTRACT_INIT_WRAPPER(9) +EXTRACT_INIT_WRAPPER(10) +EXTRACT_INIT_WRAPPER(11) +EXTRACT_INIT_WRAPPER(12) +EXTRACT_INIT_WRAPPER(13) +EXTRACT_INIT_WRAPPER(14) + +template<int index> +constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn) +{ + MeshExtract extractor = {nullptr}; + extractor.init = fn; + extractor.init_subdiv = subdiv_fn; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +#define CREATE_EXTRACTOR_ATTR(index) \ + blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \ + blender::draw::extract_attr_init_subdiv##index) + +const MeshExtract extract_attr[GPU_MAX_ATTR] = { + CREATE_EXTRACTOR_ATTR(0), + CREATE_EXTRACTOR_ATTR(1), + CREATE_EXTRACTOR_ATTR(2), + CREATE_EXTRACTOR_ATTR(3), + CREATE_EXTRACTOR_ATTR(4), + CREATE_EXTRACTOR_ATTR(5), + CREATE_EXTRACTOR_ATTR(6), + CREATE_EXTRACTOR_ATTR(7), + CREATE_EXTRACTOR_ATTR(8), + CREATE_EXTRACTOR_ATTR(9), + CREATE_EXTRACTOR_ATTR(10), + CREATE_EXTRACTOR_ATTR(11), + CREATE_EXTRACTOR_ATTR(12), + CREATE_EXTRACTOR_ATTR(13), + CREATE_EXTRACTOR_ATTR(14), +}; +} 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 index 2e2444a8e3d..8470a71059f 100644 --- 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 @@ -25,6 +25,7 @@ #include "GPU_capabilities.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -148,9 +149,8 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, 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); + float ratio = loop_edge_factor_get( + mr->poly_normals[mp_index], v1->co, mr->vert_normals[ml->v], v2->co); data->vbo_data[ml_index] = ratio * 253 + 1; } else { @@ -216,6 +216,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, MEM_SAFE_FREE(data->edge_loop_count); } +/* Different function than the one used for the non-subdivision case, as we directly take care of + * the buggy AMD driver case. */ +static GPUVertFormat *get_subdiv_edge_fac_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + if (GPU_crappy_amd_driver()) { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + else { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + } + return &format; +} + +static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx; + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPU_vertbuf_init_build_on_device( + vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + /* Create a temporary buffer for the edge original indices if it was not requested. */ + const bool has_edge_idx = edge_idx != nullptr; + GPUVertBuf *loop_edge_idx = nullptr; + if (has_edge_idx) { + loop_edge_idx = edge_idx; + } + else { + loop_edge_idx = GPU_vertbuf_calloc(); + draw_subdiv_init_origindex_buffer( + loop_edge_idx, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + 0); + } + + draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo); + + if (!has_edge_idx) { + GPU_vertbuf_discard(loop_edge_idx); + } +} + +static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + /* Make sure buffer is active for sending loose data. */ + GPU_vertbuf_use(vbo); + + uint offset = subdiv_cache->num_subdiv_loops; + for (int i = 0; i < loose_geom->edge_len; i++) { + if (GPU_crappy_amd_driver()) { + float loose_edge_fac[2] = {1.0f, 1.0f}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac); + } + else { + char loose_edge_fac[2] = {255, 255}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac); + } + + offset += 2; + } +} + constexpr MeshExtract create_extractor_edge_fac() { MeshExtract extractor = {nullptr}; @@ -224,6 +304,8 @@ constexpr MeshExtract create_extractor_edge_fac() 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.init_subdiv = extract_edge_fac_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv; extractor.finish = extract_edge_fac_finish; extractor.data_type = MR_DATA_POLY_NOR; extractor.data_size = sizeof(MeshExtract_EdgeFac_Data); 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 index 5232346e51e..0002b95c867 100644 --- 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 @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -70,11 +72,11 @@ static void mesh_render_data_edge_flag(const MeshRenderData *mr, } } - /* Use a byte for value range */ - if (mr->crease_ofs != -1) { - float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs); + /* Use half a byte for value range */ + if (mr->edge_crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->edge_crease_ofs); if (crease > 0) { - eattr->crease = (uchar)(crease * 255.0f); + eattr->crease = (uchar)ceil(crease * 15.0f); } } /* Use a byte for value range */ @@ -105,21 +107,34 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr, if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { eattr->e_flag |= VFLAG_VERT_SELECTED; } + /* Use half a byte for value range */ + if (mr->vert_crease_ofs != -1) { + float crease = BM_ELEM_CD_GET_FLOAT(eve, mr->vert_crease_ofs); + if (crease > 0) { + eattr->crease |= (uchar)ceil(crease * 15.0f) << 4; + } + } } -static void extract_edit_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static GPUVertFormat *get_edit_data_format() { - 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); + return &format; +} + +static void extract_edit_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_edit_data_format(); + 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; @@ -240,6 +255,92 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, } } +static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPU_vertbuf_init_with_format(vbo, get_edit_data_format()); + GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + *(EditLoopData **)data = vbo_data; +} + +static void extract_edit_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const BMFace *coarse_quad) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint i = start_loop_idx; i < end_loop_idx; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + + EditLoopData *edit_loop_data = &vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + if (vert_origindex != -1) { + const BMVert *eve = bm_original_vert_get(mr, vert_origindex); + if (eve) { + mesh_render_data_vert_flag(mr, eve, edit_loop_data); + } + } + + if (edge_origindex != -1) { + const BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + if (eed) { + mesh_render_data_edge_flag(mr, eed, edit_loop_data); + } + } + + /* The -1 parameter is for edit_uvs, which we don't do here. */ + mesh_render_data_face_flag(mr, coarse_quad, -1, edit_loop_data); + } +} + +static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const MPoly *coarse_quad) +{ + const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly); + BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index); + extract_edit_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm); +} + +static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *_data) +{ + if (loose_geom->edge_len == 0) { + return; + } + + EditLoopData *vbo_data = *(EditLoopData **)_data; + + for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) { + const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2; + EditLoopData *data = &vbo_data[offset]; + memset(data, 0, sizeof(EditLoopData)); + BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]); + 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]); + } +} + constexpr MeshExtract create_extractor_edit_data() { MeshExtract extractor = {nullptr}; @@ -250,6 +351,10 @@ constexpr MeshExtract create_extractor_edit_data() 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.init_subdiv = extract_edit_data_init_subdiv; + extractor.iter_subdiv_bm = extract_edit_data_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_edit_data_iter_subdiv_mesh; + extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(EditLoopData *); extractor.use_threading = true; 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 index b8494428eed..b25e40690c9 100644 --- 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 @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data { int cd_ofs; }; -static void extract_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static void extract_edituv_data_init_common(const MeshRenderData *mr, + GPUVertBuf *vbo, + MeshExtract_EditUVData_Data *data, + uint loop_len) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ @@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr, } GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); + GPU_vertbuf_data_alloc(vbo, 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_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, mr->loop_len); +} + static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, const BMFace *f, const int UNUSED(f_index), @@ -119,12 +128,66 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops); +} + +static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const BMFace *coarse_quad) +{ + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + uint start_loop_idx = subdiv_quad_index * 4; + uint end_loop_idx = (subdiv_quad_index + 1) * 4; + for (uint i = start_loop_idx; i < end_loop_idx; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + + EditLoopData *edit_loop_data = &data->vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + if (vert_origindex != -1 && edge_origindex != -1) { + BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data); + } + } +} + +static void extract_edituv_data_iter_subdiv_mesh(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data, + uint subdiv_quad_index, + const MPoly *coarse_quad) +{ + const int coarse_quad_index = static_cast<int>(coarse_quad - mr->mpoly); + BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index); + extract_edituv_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm); +} + 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.init_subdiv = extract_edituv_data_init_subdiv; + extractor.iter_subdiv_bm = extract_edituv_data_iter_subdiv_bm; + extractor.iter_subdiv_mesh = extract_edituv_data_iter_subdiv_mesh; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUVData_Data); extractor.use_threading = true; 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 index a947d98f955..49b23ff1efe 100644 --- 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 @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr } } +static GPUVertFormat *get_edituv_stretch_angle_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* Waning: adjust #UVStretchAngle struct accordingly. */ + GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + return &format; +} + +static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data)) +{ + GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer); + + GPU_vertbuf_init_build_on_device( + refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops); + + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *uvs = cache->final.buff.vbo.uv; + + /* UVs are stored contiguously so we need to compute the offset in the UVs buffer for the active + * UV layer. */ + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->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); + } + } + + int uvs_offset = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { + break; + } + + uvs_offset += 1; + } + } + + /* The data is at `offset * num loops`, and we have 2 values per index. */ + uvs_offset *= subdiv_cache->num_subdiv_loops * 2; + + draw_subdiv_build_edituv_stretch_angle_buffer( + subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo); +} + 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.init_subdiv = extract_edituv_stretch_angle_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_StretchAngle_Data); extractor.use_threading = false; 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 index 3db8cd79af5..c116fa5ba07 100644 --- 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 @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t 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)) +static void compute_area_ratio(const MeshRenderData *mr, + float *r_area_ratio, + float &r_tot_area, + float &r_tot_uv_area) { - 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; @@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, 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); + r_area_ratio[f] = area_ratio_get(area, uvarea); } } else { @@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, 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); + r_area_ratio[mp_index] = area_ratio_get(area, uvarea); } } - cache->tot_area = tot_area; - cache->tot_uv_area = tot_uv_area; + r_tot_area = tot_area; + r_tot_uv_area = tot_uv_area; +} + +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 *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); + compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area); /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; @@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, MEM_freeN(area_ratio); } +static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + + /* Initialize final buffer. */ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + /* Initialize coarse data buffer. */ + + GPUVertBuf *coarse_data = GPU_vertbuf_calloc(); + + /* We use the same format as we just copy data around. */ + GPU_vertbuf_init_with_format(coarse_data, &format); + GPU_vertbuf_data_alloc(coarse_data, mr->loop_len); + + compute_area_ratio(mr, + static_cast<float *>(GPU_vertbuf_get_data(coarse_data)), + cache->tot_area, + cache->tot_uv_area); + + draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo); + + GPU_vertbuf_discard(coarse_data); +} + 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.init_subdiv = extract_edituv_stretch_area_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; 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 index fed66f0057d..b2ebff08abf 100644 --- 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 @@ -28,6 +28,7 @@ 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 @@ -114,6 +115,7 @@ constexpr MeshExtract create_extractor_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, 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 index 33f9180e122..f65159f9b95 100644 --- 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 @@ -23,24 +23,40 @@ #include "extract_mesh.h" +#include "draw_subdivision.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) +static GPUVertFormat *get_fdots_pos_format() { - 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); } + return &format; +} + +static GPUVertFormat *get_fdots_nor_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &format; +} - GPU_vertbuf_init_with_format(vbo, &format); +static void extract_fdots_pos_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_fdots_pos_format(); + 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); @@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + /* We "extract" positions, normals, and indices at once. */ + GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor; + GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots; + + GPU_vertbuf_init_build_on_device( + fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly); + GPU_vertbuf_init_build_on_device( + fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly); + GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly); + draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo); +} + constexpr MeshExtract create_extractor_fdots_pos() { MeshExtract extractor = {nullptr}; extractor.init = extract_fdots_pos_init; + extractor.init_subdiv = extract_fdots_init_subdiv; 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; 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 index f9f66c27aaa..93b94b210b2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -23,6 +23,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -85,7 +87,7 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, *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); + *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]); } else { *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]); @@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, } } +static GPUVertFormat *get_subdiv_lnor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + BLI_assert(pos_nor); + GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops); + draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo); +} + constexpr MeshExtract create_extractor_lnor() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_init; + extractor.init_subdiv = extract_lnor_init_subdiv; 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; @@ -121,6 +147,7 @@ constexpr MeshExtract create_extractor_lnor() } /** \} */ + /* ---------------------------------------------------------------------- */ /** \name Extract HQ Loop Normal * \{ */ @@ -183,7 +210,7 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, 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); + normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]); } else { normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]); @@ -209,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_hq_init; + extractor.init_subdiv = extract_lnor_init_subdiv; 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; 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 index 33a33c81bc2..706c6ad5403 100644 --- 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 @@ -460,7 +460,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort) float fac = -1.0f; if (mp->totloop > 3) { - float *f_no = mr->poly_normals[mp_index]; + const float *f_no = mr->poly_normals[mp_index]; fac = 0.0f; for (int i = 1; i <= mp->totloop; i++) { @@ -555,7 +555,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp) 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]; + *pval = (void *)mr->poly_normals[mp_index]; /* non-manifold edge, yet... */ continue; } 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 index eb9a138590c..5d2ea923658 100644 --- 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 @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -72,9 +74,8 @@ static void extract_pos_nor_init(const MeshRenderData *mr, } } 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); + for (int v = 0; v < mr->vert_len; v++) { + data->normals[v].low = GPU_normal_convert_i10_v3(mr->vert_normals[v]); } } } @@ -194,6 +195,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->normals); } +static GPUVertFormat *get_pos_nor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "vnor"); + } + return &format; +} + +static GPUVertFormat *get_normals_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const bool do_limit_normals = subdiv_cache->do_limit_normals; + + /* Initialize the vertex buffer, it was already allocated. */ + GPU_vertbuf_init_build_on_device( + vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals); + + if (!do_limit_normals) { + /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */ + GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer( + subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *vertex_normals = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts); + + draw_subdiv_accumulate_normals(subdiv_cache, + vbo, + subdiv_cache->subdiv_vertex_face_adjacency_offsets, + subdiv_cache->subdiv_vertex_face_adjacency, + vertex_normals); + + draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo); + + GPU_vertbuf_discard(vertex_normals); + GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index); + } +} + +static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + const MVert *coarse_verts = coarse_mesh->mvert; + uint offset = subdiv_cache->num_subdiv_loops; + + /* TODO(kevindietrich) : replace this when compressed normals are supported. */ + struct SubdivPosNorLoop { + float pos[3]; + float nor[3]; + float flag; + }; + + SubdivPosNorLoop edge_data[2]; + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + const MVert *loose_vert1 = &coarse_verts[loose_edge->v1]; + const MVert *loose_vert2 = &coarse_verts[loose_edge->v2]; + + copy_v3_v3(edge_data[0].pos, loose_vert1->co); + copy_v3_v3(edge_data[0].nor, mr->vert_normals[loose_edge->v1]); + edge_data[0].flag = 0.0f; + + copy_v3_v3(edge_data[1].pos, loose_vert2->co); + copy_v3_v3(edge_data[1].nor, mr->vert_normals[loose_edge->v2]); + edge_data[1].flag = 0.0f; + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data); + + offset += 2; + } + + SubdivPosNorLoop vert_data; + vert_data.flag = 0.0f; + for (int i = 0; i < loose_geom->vert_len; i++) { + const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]]; + + copy_v3_v3(vert_data.pos, loose_vertex->co); + copy_v3_v3(vert_data.nor, mr->vert_normals[loose_geom->verts[i]]); + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data); + + offset += 1; + } +} + constexpr MeshExtract create_extractor_pos_nor() { MeshExtract extractor = {nullptr}; @@ -205,6 +323,8 @@ constexpr MeshExtract create_extractor_pos_nor() 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.init_subdiv = extract_pos_nor_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_PosNor_Data); extractor.use_threading = true; @@ -259,9 +379,8 @@ static void extract_pos_nor_hq_init(const MeshRenderData *mr, } } 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); + for (int v = 0; v < mr->vert_len; v++) { + normal_float_to_short_v3(data->normals[v].high, mr->vert_normals[v]); } } } @@ -391,6 +510,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_pos_nor_hq_init; + extractor.init_subdiv = extract_pos_nor_init_subdiv; 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; 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 index fd91bc5258f..753fbe7e0e2 100644 --- 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 @@ -27,6 +27,7 @@ #include "BKE_paint.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -35,13 +36,23 @@ namespace blender::draw { /** \name Extract Sculpt Data * \{ */ +static GPUVertFormat *get_sculpt_data_format() +{ + static GPUVertFormat format = {0}; + 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); + } + return &format; +} + 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}; + GPUVertFormat *format = get_sculpt_data_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; @@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, 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_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); struct gpuSculptData { @@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, } } +static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + Mesh *coarse_mesh = mr->me; + CustomData *cd_vdata = &coarse_mesh->vdata; + CustomData *cd_pdata = &coarse_mesh->pdata; + + /* First, interpolate mask if available. */ + GPUVertBuf *mask_vbo = nullptr; + GPUVertBuf *subdiv_mask_vbo = nullptr; + float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); + + if (cd_mask) { + GPUVertFormat mask_format = {0}; + GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + + mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(mask_vbo, &mask_format); + GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop); + float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + *v_mask++ = cd_mask[ml->v]; + } + } + + subdiv_mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops); + + draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0); + } + + /* Then, gather face sets. */ + GPUVertFormat face_set_format = {0}; + GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format); + GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops); + + struct gpuFaceSet { + uint8_t color[4]; + }; + + gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo); + int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); + + GPUVertFormat *format = get_sculpt_data_format(); + GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int mp_index = subdiv_loop_poly_index[i]; + + 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 != coarse_mesh->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + face_set_id, coarse_mesh->face_sets_color_seed, face_set_color); + } + } + copy_v3_v3_uchar(face_sets->color, face_set_color); + face_sets++; + } + + /* Finally, interleave mask and face sets. */ + draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo); + + if (mask_vbo) { + GPU_vertbuf_discard(mask_vbo); + GPU_vertbuf_discard(subdiv_mask_vbo); + } + GPU_vertbuf_discard(face_set_vbo); +} + constexpr MeshExtract create_extractor_sculpt_data() { MeshExtract extractor = {nullptr}; extractor.init = extract_sculpt_data_init; + extractor.init_subdiv = extract_sculpt_data_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; 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 index 5ac30dd3be9..33c27b45627 100644 --- 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 @@ -21,6 +21,7 @@ * \ingroup draw */ +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, (*(uint32_t **)data)[offset + lvert_index] = v_orig; } +static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + /* Each element points to an element in the ibo.points. */ + draw_subdiv_init_origindex_buffer(vbo, + subdiv_cache->subdiv_loop_subdiv_vert_index, + subdiv_cache->num_subdiv_loops, + mr->loop_loose_len); +} + +static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + vert_idx_data[offset] = loose_edge->v1; + vert_idx_data[offset + 1] = loose_edge->v2; + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + vert_idx_data[offset] = loose_geom->verts[i]; + offset += 1; + } +} + +static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + mr->edge_loose_len * 2); +} + +static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + vert_idx_data[offset] = loose_geom->edges[i]; + vert_idx_data[offset + 1] = loose_geom->edges[i]; + offset += 2; + } +} + +static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0); +} + 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.init_subdiv = extract_poly_idx_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx() 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.init_subdiv = extract_edge_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx() 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.init_subdiv = extract_vert_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; 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 index 1f8776fc98e..03d1b327689 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -54,11 +54,18 @@ static void extract_tan_ex_init(const MeshRenderData *mr, 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; + bool use_orco_tan = cache->cd_used.tan_orco != 0; int tan_len = 0; char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME]; + /* FIXME(T91838): This is to avoid a crash when orco tangent was requested but there are valid + * uv layers. It would be better to fix the root cause. */ + if (tan_layers == 0 && use_orco_tan && CustomData_get_layer_index(cd_ldata, CD_MLOOPUV) != -1) { + tan_layers = 1; + use_orco_tan = false; + } + 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]; @@ -131,6 +138,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr, calc_active_tangent, tangent_names, tan_len, + mr->vert_normals, mr->poly_normals, mr->loop_normals, orco, 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 index af279b08a59..6e9d8ef6926 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -23,6 +23,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -31,25 +32,27 @@ namespace blender::draw { /** \name Extract UV layers * \{ */ -static void extract_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the vertex format to be used for UVs. Return true if any UV layer is + * found, false otherwise. */ +static bool mesh_extract_uv_format_init(GPUVertFormat *format, + struct MeshBatchCache *cache, + CustomData *cd_ldata, + eMRExtractType extract_type, + uint32_t &r_uv_layers) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + 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) { + if (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); } } + r_uv_layers = uv_layers; + 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]; @@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr, 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); + 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); + 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"); + 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"); + GPU_vertformat_alias_add(format, "au"); /* Alias to `pos` for edit uvs. */ - GPU_vertformat_alias_add(&format, "pos"); + 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"); + GPU_vertformat_alias_add(format, "mu"); } } } + if (format->attr_len == 0) { + GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + return false; + } + + return true; +} + +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}; + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; int v_len = mr->loop_len; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint32_t uv_layers = cache->cd_used.uv; + if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) { /* VBO will not be used, only allocate minimum of memory. */ v_len = 1; } @@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr, } } +static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertFormat format = {0}; + + uint v_len = subdiv_cache->num_subdiv_loops; + uint uv_layers; + if (!mesh_extract_uv_format_init( + &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) { + // TODO(kevindietrich): handle this more gracefully. + v_len = 1; + } + + GPU_vertbuf_init_build_on_device(vbo, &format, v_len); + + if (uv_layers == 0) { + return; + } + + /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++; + draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset); + } + } +} + constexpr MeshExtract create_extractor_uv() { MeshExtract extractor = {nullptr}; extractor.init = extract_uv_init; + extractor.init_subdiv = extract_uv_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; 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 index 2c7770c8e72..a0307b9b2cd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -25,6 +25,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -33,19 +34,14 @@ namespace blender::draw { /** \name Extract VCol * \{ */ -static void extract_vcol_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */ +static void init_vcol_format(GPUVertFormat *format, + const MeshBatchCache *cache, + CustomData *cd_ldata) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + 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; + const uint32_t vcol_layers = cache->cd_used.vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -54,61 +50,57 @@ static void extract_vcol_init(const MeshRenderData *mr, 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); + 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"); + GPU_vertformat_alias_add(format, "c"); } if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "ac"); + 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) { + /* 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_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); +/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision + * case. */ +static GPUVertFormat *get_coarse_vcol_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "c"); + GPU_vertformat_alias_add(&format, "ac"); + } + return &format; +} - 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); +using gpuMeshVcol = struct gpuMeshVcol { + ushort r, g, b, a; +}; - 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); - } - } - } - } +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}; + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + const uint32_t vcol_layers = cache->cd_used.vcol; + init_vcol_format(&format, cache, cd_ldata); GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); - using gpuMeshVcol = struct gpuMeshVcol { - ushort r, g, b, a; - }; - 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)) { @@ -139,42 +131,67 @@ static void extract_vcol_init(const MeshRenderData *mr, } } } + } +} - 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]); - } +static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + Mesh *coarse_mesh = subdiv_cache->mesh; + + GPUVertFormat format = {0}; + init_vcol_format(&format, cache, &coarse_mesh->ldata); + + GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + /* Dynamic as we upload and interpolate layers one at a time. */ + GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC); + + GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop); + + gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data); + + const CustomData *cd_ldata = &coarse_mesh->ldata; + + const uint vcol_layers = cache->cd_used.vcol; + + /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in + * a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (vcol_layers & (1 << i)) { + /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */ + const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++; + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + + gpuMeshVcol *vcol = mesh_vcol; + + for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) { + vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); } + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset); } } + + GPU_vertbuf_discard(src_data); } constexpr MeshExtract create_extractor_vcol() { MeshExtract extractor = {nullptr}; extractor.init = extract_vcol_init; + extractor.init_subdiv = extract_vcol_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; 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 index bdb1410a755..bb8853b8154 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -25,6 +25,7 @@ #include "BKE_deform.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + 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_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *coarse_weights = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(coarse_weights, &format); + GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop); + float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights)); + + const DRW_MeshWeightState *wstate = &cache->weight_state; + const MDeformVert *dverts = static_cast<const MDeformVert *>( + CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + + if (dverts != nullptr) { + const MDeformVert *dvert = &dverts[ml->v]; + coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate); + } + else { + coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate); + } + } + } + + draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0); + + GPU_vertbuf_discard(coarse_weights); +} + constexpr MeshExtract create_extractor_weights() { MeshExtract extractor = {nullptr}; extractor.init = extract_weights_init; + extractor.init_subdiv = extract_weights_init_subdiv; extractor.iter_poly_bm = extract_weights_iter_poly_bm; extractor.iter_poly_mesh = extract_weights_iter_poly_mesh; extractor.data_type = MR_DATA_NONE; |