Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/intern/draw_cache_impl_mesh.c
| Show All 28 Lines | |||||
| * \brief Mesh API for render engines | * \brief Mesh API for render engines | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | ||||
| #include "BLI_math_bits.h" | #include "BLI_math_bits.h" | ||||
| #include "BLI_math_color.h" | |||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_alloca.h" | #include "BLI_alloca.h" | ||||
| #include "BLI_edgehash.h" | #include "BLI_edgehash.h" | ||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| ▲ Show 20 Lines • Show All 1,051 Lines • ▼ Show 20 Lines | else { | ||||
| /* exceptional value, unclamped or nan, | /* exceptional value, unclamped or nan, | ||||
| * avoid uninitialized memory use */ | * avoid uninitialized memory use */ | ||||
| r_rgb[0] = 1.0f; | r_rgb[0] = 1.0f; | ||||
| r_rgb[1] = 0.0f; | r_rgb[1] = 0.0f; | ||||
| r_rgb[2] = 1.0f; | r_rgb[2] = 1.0f; | ||||
| } | } | ||||
| } | } | ||||
| static void vertex_weight_color(float vweight[3], float weight, bool show_alert_color) | |||||
| { | |||||
| CLAMP(weight, 0.0f, 1.0f); | |||||
| if (show_alert_color) { | |||||
| bTheme *theme = U.themes.first; | |||||
| rgb_uchar_to_float(vweight, (unsigned char*)theme->tv3d.vertex_unreferenced); | |||||
| } | |||||
| else if (U.flag & USER_CUSTOM_RANGE) { | |||||
| BKE_colorband_evaluate(&U.coba_weight, weight, vweight); | |||||
| } | |||||
| else { | |||||
| rgb_from_weight(vweight, weight); | |||||
| } | |||||
| } | |||||
| static void evaluate_vertex_weight(float vweight[3], const MDeformVert *dvert, const VertexWeightSelection *vwsel) | |||||
| { | |||||
| float input = 0.0f; | |||||
| bool show_alert_color = false; | |||||
| if (vwsel->flags & VWEIGHT_MULTIPAINT) { | |||||
| /* Multi-Paint feature */ | |||||
| input = BKE_defvert_multipaint_collective_weight( | |||||
| dvert, vwsel->defgroup_tot, vwsel->defgroup_sel, vwsel->defgroup_sel_tot, (vwsel->flags & VWEIGHT_AUTO_NORMALIZE) != 0); | |||||
| /* make it black if the selected groups have no weight on a vertex */ | |||||
| if (input == 0.0f) { | |||||
| show_alert_color = true; | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* default, non tricky behavior */ | |||||
| input = defvert_find_weight(dvert, vwsel->defgroup_active); | |||||
| if (input == 0.0f) { | |||||
| switch (vwsel->alert_mode) { | |||||
| case OB_DRAW_GROUPUSER_ACTIVE: | |||||
| show_alert_color = true; | |||||
| break; | |||||
| case OB_DRAW_GROUPUSER_ALL: | |||||
| show_alert_color = defvert_is_weight_zero(dvert, vwsel->defgroup_tot); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| vertex_weight_color(vweight, input, show_alert_color); | |||||
| } | |||||
| /* color-code for missing data (full brightness isn't easy on the eye). */ | |||||
| static const unsigned char missing_weight_color[3] = { 0xa0, 0x00, 0xa0 }; | |||||
| /** Ensure #MeshRenderData.vert_weight_color */ | /** Ensure #MeshRenderData.vert_weight_color */ | ||||
| static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, const int defgroup) | static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, const VertexWeightSelection *vwsel) | ||||
| { | { | ||||
| float (*vweight)[3] = rdata->vert_weight_color; | float (*vweight)[3] = rdata->vert_weight_color; | ||||
| if (vweight == NULL) { | if (vweight == NULL) { | ||||
| if (defgroup == -1) { | if (vwsel->defgroup_active == -1) { | ||||
| goto fallback; | goto fallback; | ||||
| } | } | ||||
| if (rdata->edit_bmesh) { | if (rdata->edit_bmesh) { | ||||
| BMesh *bm = rdata->edit_bmesh->bm; | BMesh *bm = rdata->edit_bmesh->bm; | ||||
| const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); | const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); | ||||
| if (cd_dvert_offset == -1) { | if (cd_dvert_offset == -1) { | ||||
| goto fallback; | goto fallback; | ||||
| } | } | ||||
| BMIter viter; | BMIter viter; | ||||
| BMVert *eve; | BMVert *eve; | ||||
| int i; | int i; | ||||
| vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); | vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); | ||||
| BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) { | BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) { | ||||
| const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); | const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); | ||||
| float weight = defvert_find_weight(dvert, defgroup); | evaluate_vertex_weight(vweight[i], dvert, vwsel); | ||||
| if (U.flag & USER_CUSTOM_RANGE) { | |||||
| BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); | |||||
| } | |||||
| else { | |||||
| rgb_from_weight(vweight[i], weight); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (rdata->dvert == NULL) { | if (rdata->dvert == NULL) { | ||||
| goto fallback; | goto fallback; | ||||
| } | } | ||||
| vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); | vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); | ||||
| for (int i = 0; i < rdata->vert_len; i++) { | for (int i = 0; i < rdata->vert_len; i++) { | ||||
| float weight = defvert_find_weight(&rdata->dvert[i], defgroup); | evaluate_vertex_weight(vweight[i], &rdata->dvert[i], vwsel); | ||||
| if (U.flag & USER_CUSTOM_RANGE) { | |||||
| BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); | |||||
| } | |||||
| else { | |||||
| rgb_from_weight(vweight[i], weight); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return; | return; | ||||
| fallback: | fallback: | ||||
| vweight = rdata->vert_weight_color = MEM_callocN(sizeof(*vweight) * rdata->vert_len, __func__); | vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); | ||||
| float error_color[3]; | |||||
| if ((vwsel->defgroup_active < 0) && (vwsel->defgroup_tot > 0)) { | |||||
| rgb_uchar_to_float(error_color, missing_weight_color); | |||||
| } | |||||
| else { | |||||
| vertex_weight_color(error_color, 0.0f, vwsel->alert_mode != OB_DRAW_GROUPUSER_NONE); | |||||
| } | |||||
| for (int i = 0; i < rdata->vert_len; i++) { | for (int i = 0; i < rdata->vert_len; i++) { | ||||
| vweight[i][2] = 0.5f; | copy_v3_v3(vweight[i], error_color); | ||||
| } | } | ||||
| } | } | ||||
| /** Ensure #MeshRenderData.edge_select_bool */ | /** Ensure #MeshRenderData.edge_select_bool */ | ||||
| static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool use_wire) | static void mesh_render_data_ensure_edge_select_bool(MeshRenderData *rdata, bool use_wire) | ||||
| { | { | ||||
| bool *edge_select_bool = rdata->edge_select_bool; | bool *edge_select_bool = rdata->edge_select_bool; | ||||
| if (edge_select_bool == NULL) { | if (edge_select_bool == NULL) { | ||||
| ▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | if (vbo_data) { | ||||
| uchar vflag[4] = {0, 0, 0, 0}; | uchar vflag[4] = {0, 0, 0, 0}; | ||||
| vflag[0] = mesh_render_data_vertex_flag(rdata, eve); | vflag[0] = mesh_render_data_vertex_flag(rdata, eve); | ||||
| GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag); | GPU_vertbuf_attr_set(vbo_data, data_id, base_vert_idx, vflag); | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* ---------------------------------------------------------------------- */ | |||||
| /** \name Vertex Group Selection | |||||
| * \{ */ | |||||
| /** Reset the selection structure, deallocating heap memory as appropriate. */ | |||||
| void DRW_vweight_selection_clear(struct VertexWeightSelection *sel) | |||||
| { | |||||
| MEM_SAFE_FREE(sel->defgroup_sel); | |||||
| memset(sel, 0, sizeof(VertexWeightSelection)); | |||||
| sel->defgroup_active = -1; | |||||
| } | |||||
| /** Copy selection data from one structure to another, including heap memory. */ | |||||
| void DRW_vweight_selection_copy(struct VertexWeightSelection *sel, const struct VertexWeightSelection *src) | |||||
| { | |||||
| MEM_SAFE_FREE(sel->defgroup_sel); | |||||
| memcpy(sel, src, sizeof(VertexWeightSelection)); | |||||
| if (src->defgroup_sel) { | |||||
| sel->defgroup_sel = MEM_dupallocN(src->defgroup_sel); | |||||
| } | |||||
| } | |||||
| /** Compare two selection structures. */ | |||||
| bool DRW_vweight_selection_compare(const struct VertexWeightSelection *a, const struct VertexWeightSelection *b) | |||||
| { | |||||
| return a->defgroup_active == b->defgroup_active && | |||||
| a->defgroup_tot == b->defgroup_tot && | |||||
| a->flags == b->flags && | |||||
| a->alert_mode == b->alert_mode && | |||||
| a->defgroup_sel_tot == b->defgroup_sel_tot && | |||||
| ((!a->defgroup_sel && !b->defgroup_sel) || | |||||
| (a->defgroup_sel && b->defgroup_sel && | |||||
| memcmp(a->defgroup_sel, b->defgroup_sel, a->defgroup_tot * sizeof(bool)) == 0)); | |||||
campbellbarton: This seems quite an expensive function to run on every access (called indirectly via… | |||||
| } | |||||
| /** \} */ | |||||
| /* ---------------------------------------------------------------------- */ | /* ---------------------------------------------------------------------- */ | ||||
| /** \name Mesh GPUBatch Cache | /** \name Mesh GPUBatch Cache | ||||
| * \{ */ | * \{ */ | ||||
| typedef struct MeshBatchCache { | typedef struct MeshBatchCache { | ||||
| GPUVertBuf *pos_in_order; | GPUVertBuf *pos_in_order; | ||||
| ▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | typedef struct MeshBatchCache { | ||||
| bool is_maybe_dirty; | bool is_maybe_dirty; | ||||
| bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ | bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ | ||||
| int edge_len; | int edge_len; | ||||
| int tri_len; | int tri_len; | ||||
| int poly_len; | int poly_len; | ||||
| int vert_len; | int vert_len; | ||||
| int mat_len; | int mat_len; | ||||
| bool is_editmode; | bool is_editmode; | ||||
| int vertex_group_index; | |||||
| VertexWeightSelection vertex_weight_selection; | |||||
| /* XXX, only keep for as long as sculpt mode uses shaded drawing. */ | /* XXX, only keep for as long as sculpt mode uses shaded drawing. */ | ||||
| bool is_sculpt_points_tag; | bool is_sculpt_points_tag; | ||||
| /* Valid only if edges_adjacency is up to date. */ | /* Valid only if edges_adjacency is up to date. */ | ||||
| bool is_manifold; | bool is_manifold; | ||||
| } MeshBatchCache; | } MeshBatchCache; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (cache->is_editmode == false) { | ||||
| cache->poly_len = mesh_render_polys_len_get(me); | cache->poly_len = mesh_render_polys_len_get(me); | ||||
| cache->vert_len = mesh_render_verts_len_get(me); | cache->vert_len = mesh_render_verts_len_get(me); | ||||
| } | } | ||||
| cache->mat_len = mesh_render_mat_len_get(me); | cache->mat_len = mesh_render_mat_len_get(me); | ||||
| cache->is_maybe_dirty = false; | cache->is_maybe_dirty = false; | ||||
| cache->is_dirty = false; | cache->is_dirty = false; | ||||
| cache->vertex_group_index = -1; | |||||
| DRW_vweight_selection_clear(&cache->vertex_weight_selection); | |||||
| } | } | ||||
| static MeshBatchCache *mesh_batch_cache_get(Mesh *me) | static MeshBatchCache *mesh_batch_cache_get(Mesh *me) | ||||
| { | { | ||||
| if (!mesh_batch_cache_valid(me)) { | if (!mesh_batch_cache_valid(me)) { | ||||
| mesh_batch_cache_clear(me); | mesh_batch_cache_clear(me); | ||||
| mesh_batch_cache_init(me); | mesh_batch_cache_init(me); | ||||
| } | } | ||||
| return me->runtime.batch_cache; | return me->runtime.batch_cache; | ||||
| } | } | ||||
| static MeshBatchCache *mesh_batch_cache_get__check_vertex_group(Mesh *me, int defgroup) | static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache, const VertexWeightSelection *vwsel) | ||||
Done Inline Actions"__" in function name ? Not sure if that follows our codestyle. fclem: "__" in function name ? Not sure if that follows our codestyle. | |||||
Not Done Inline ActionsI'm not sure if this is correct, but to address the general concerns of D3723, I changed it to discard just the weight batch when the selection is different. If this approach is valid, I wonder if the actual weight painting could do this too (or maybe it already does?). angavrilov: I'm not sure if this is correct, but to address the general concerns of D3723, I changed it to… | |||||
| { | { | ||||
| MeshBatchCache *cache = mesh_batch_cache_get(me); | if (!DRW_vweight_selection_compare(&cache->vertex_weight_selection, vwsel)) { | ||||
| if (cache->vertex_group_index != defgroup) { | GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights); | ||||
| cache->is_dirty = true; | |||||
| DRW_vweight_selection_clear(&cache->vertex_weight_selection); | |||||
| } | } | ||||
| return mesh_batch_cache_get(me); | |||||
| } | } | ||||
| static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) | static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) | ||||
| { | { | ||||
| GPU_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data); | GPU_VERTBUF_DISCARD_SAFE(cache->shaded_triangles_data); | ||||
| if (cache->shaded_triangles_in_order) { | if (cache->shaded_triangles_in_order) { | ||||
| for (int i = 0; i < cache->mat_len; ++i) { | for (int i = 0; i < cache->mat_len; ++i) { | ||||
| GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]); | GPU_INDEXBUF_DISCARD_SAFE(cache->shaded_triangles_in_order[i]); | ||||
| ▲ Show 20 Lines • Show All 161 Lines • ▼ Show 20 Lines | if (cache->texpaint_triangles) { | ||||
| for (int i = 0; i < cache->mat_len; ++i) { | for (int i = 0; i < cache->mat_len; ++i) { | ||||
| GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); | GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); | ||||
| } | } | ||||
| } | } | ||||
| MEM_SAFE_FREE(cache->texpaint_triangles); | MEM_SAFE_FREE(cache->texpaint_triangles); | ||||
| GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); | GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); | ||||
| DRW_vweight_selection_clear(&cache->vertex_weight_selection); | |||||
| } | } | ||||
| void DRW_mesh_batch_cache_free(Mesh *me) | void DRW_mesh_batch_cache_free(Mesh *me) | ||||
| { | { | ||||
| mesh_batch_cache_clear(me); | mesh_batch_cache_clear(me); | ||||
| MEM_SAFE_FREE(me->runtime.batch_cache); | MEM_SAFE_FREE(me->runtime.batch_cache); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 740 Lines • ▼ Show 20 Lines | if (vbo_len_used != vbo_len_capacity) { | ||||
| GPU_vertbuf_data_resize(vbo, vbo_len_used); | GPU_vertbuf_data_resize(vbo, vbo_len_used); | ||||
| } | } | ||||
| } | } | ||||
| return vbo; | return vbo; | ||||
| } | } | ||||
| static GPUVertBuf *mesh_create_tri_weights( | static GPUVertBuf *mesh_create_tri_weights( | ||||
| MeshRenderData *rdata, bool use_hide, int defgroup) | MeshRenderData *rdata, bool use_hide, const VertexWeightSelection *vwsel) | ||||
| { | { | ||||
| BLI_assert( | BLI_assert( | ||||
| rdata->types & | rdata->types & | ||||
| (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT)); | (MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT)); | ||||
| GPUVertBuf *vbo; | GPUVertBuf *vbo; | ||||
| { | { | ||||
| uint cidx = 0; | uint cidx = 0; | ||||
| static GPUVertFormat format = { 0 }; | static GPUVertFormat format = { 0 }; | ||||
| static struct { uint col; } attr_id; | static struct { uint col; } attr_id; | ||||
| if (format.attr_len == 0) { | if (format.attr_len == 0) { | ||||
| attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | attr_id.col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); | ||||
| } | } | ||||
| vbo = GPU_vertbuf_create_with_format(&format); | vbo = GPU_vertbuf_create_with_format(&format); | ||||
| const int tri_len = mesh_render_data_looptri_len_get(rdata); | const int tri_len = mesh_render_data_looptri_len_get(rdata); | ||||
| const int vbo_len_capacity = tri_len * 3; | const int vbo_len_capacity = tri_len * 3; | ||||
| int vbo_len_used = 0; | int vbo_len_used = 0; | ||||
| GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); | GPU_vertbuf_data_alloc(vbo, vbo_len_capacity); | ||||
| mesh_render_data_ensure_vert_weight_color(rdata, defgroup); | mesh_render_data_ensure_vert_weight_color(rdata, vwsel); | ||||
| const float (*vert_weight_color)[3] = rdata->vert_weight_color; | const float (*vert_weight_color)[3] = rdata->vert_weight_color; | ||||
| if (rdata->edit_bmesh) { | if (rdata->edit_bmesh) { | ||||
| for (int i = 0; i < tri_len; i++) { | for (int i = 0; i < tri_len; i++) { | ||||
| const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; | const BMLoop **ltri = (const BMLoop **)rdata->edit_bmesh->looptris[i]; | ||||
| /* Assume 'use_hide' */ | /* Assume 'use_hide' */ | ||||
| if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { | if (!BM_elem_flag_test(ltri[0]->f, BM_ELEM_HIDDEN)) { | ||||
| for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { | for (uint tri_corner = 0; tri_corner < 3; tri_corner++) { | ||||
| ▲ Show 20 Lines • Show All 1,152 Lines • ▼ Show 20 Lines | cache->ledges_with_normals = GPU_batch_create( | ||||
| mesh_batch_cache_get_loose_edges(rdata, cache)); | mesh_batch_cache_get_loose_edges(rdata, cache)); | ||||
| mesh_render_data_free(rdata); | mesh_render_data_free(rdata); | ||||
| } | } | ||||
| return cache->ledges_with_normals; | return cache->ledges_with_normals; | ||||
| } | } | ||||
| GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(Mesh *me, int defgroup) | GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(Mesh *me, const VertexWeightSelection *vwsel) | ||||
| { | { | ||||
| MeshBatchCache *cache = mesh_batch_cache_get__check_vertex_group(me, defgroup); | MeshBatchCache *cache = mesh_batch_cache_get(me); | ||||
| mesh_batch_cache_check_vertex_group(cache, vwsel); | |||||
| if (cache->triangles_with_weights == NULL) { | if (cache->triangles_with_weights == NULL) { | ||||
| const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0; | const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0; | ||||
| const int datatype = | const int datatype = | ||||
| MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT; | MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY | MR_DATATYPE_DVERT; | ||||
| MeshRenderData *rdata = mesh_render_data_create(me, datatype); | MeshRenderData *rdata = mesh_render_data_create(me, datatype); | ||||
| cache->triangles_with_weights = GPU_batch_create_ex( | cache->triangles_with_weights = GPU_batch_create_ex( | ||||
| GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, defgroup), NULL, GPU_BATCH_OWNS_VBO); | GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, vwsel), NULL, GPU_BATCH_OWNS_VBO); | ||||
| cache->vertex_group_index = defgroup; | |||||
| DRW_vweight_selection_copy(&cache->vertex_weight_selection, vwsel); | |||||
| GPUVertBuf *vbo_tris = use_hide ? | GPUVertBuf *vbo_tris = use_hide ? | ||||
| mesh_create_tri_pos_and_normals_visible_only(rdata) : | mesh_create_tri_pos_and_normals_visible_only(rdata) : | ||||
| mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); | mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); | ||||
| GPU_batch_vertbuf_add_ex(cache->triangles_with_weights, vbo_tris, use_hide); | GPU_batch_vertbuf_add_ex(cache->triangles_with_weights, vbo_tris, use_hide); | ||||
| mesh_render_data_free(rdata); | mesh_render_data_free(rdata); | ||||
| ▲ Show 20 Lines • Show All 594 Lines • Show Last 20 Lines | |||||
This seems quite an expensive function to run on every access (called indirectly via DRW_cache_mesh_surface_weights_get).