diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2018-09-23 20:41:10 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2018-09-25 18:44:57 +0300 |
commit | af998b40a0d1cd1615ab836c6214523169d4dd42 (patch) | |
tree | 1c2a05cf7fa7ccf7b35e8501eba5a99ab5e51071 | |
parent | bd51cada8db64e45cabca66cd61438c1ae2bdf25 (diff) |
Implement correct drawing of advanced Weight display features.
This adds existing behavior from calc_weightpaint_vert_array
that was missing from the new rendering code:
- No selected Vertex Group displays as a solid pink color.
- Zero weight displays as alert color depending on Options.
- Multipaint mode correctly displays collective weight.
In order to properly implement this variety, a data structure
holding all relevant parameters is introduced.
Reviewers: fclem, campbellbarton
Subscribers: jbakker
Differential Revision: https://developer.blender.org/D3722
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 43 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 25 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 161 | ||||
-rw-r--r-- | source/blender/draw/modes/edit_mesh_mode.c | 2 | ||||
-rw-r--r-- | source/blender/draw/modes/paint_weight_mode.c | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_mesh.c | 1 |
7 files changed, 198 insertions, 38 deletions
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index c4214b436f1..abc62c7e175 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -37,11 +37,16 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_listbase.h" + +#include "BKE_object_deform.h" #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_batch_utils.h" +#include "MEM_guardedalloc.h" + #include "draw_cache.h" #include "draw_cache_impl.h" @@ -2950,12 +2955,46 @@ GPUBatch *DRW_cache_mesh_loose_edges_get(Object *ob) return DRW_mesh_batch_cache_get_loose_edges_with_normals(me); } -GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob) +GPUBatch *DRW_cache_mesh_surface_weights_get(Object *ob, ToolSettings *ts, bool paint_mode) { BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, ob->actdef - 1); + + /* Extract complete vertex weight group selection state and mode flags. */ + VertexWeightSelection vwsel; + memset(&vwsel, 0, sizeof(vwsel)); + + vwsel.defgroup_active = ob->actdef - 1; + vwsel.defgroup_tot = BLI_listbase_count(&ob->defbase); + + vwsel.alert_mode = ts->weightuser; + + if (paint_mode && ts->multipaint) { + /* Multipaint needs to know all selected bones, not just the active group. + * This is actually a relatively expensive operation, but caching would be difficult. */ + vwsel.defgroup_sel = BKE_object_defgroup_selected_get(ob, vwsel.defgroup_tot, &vwsel.defgroup_sel_tot); + + if (vwsel.defgroup_sel_tot > 1) { + vwsel.flags |= VWEIGHT_MULTIPAINT | (ts->auto_normalize ? VWEIGHT_AUTO_NORMALIZE : 0); + + if (me->editflag & ME_EDIT_MIRROR_X) { + BKE_object_defgroup_mirror_selection(ob, vwsel.defgroup_tot, vwsel.defgroup_sel, vwsel.defgroup_sel, &vwsel.defgroup_sel_tot); + } + } + /* With only one selected bone Multipaint reverts to regular mode. */ + else { + vwsel.defgroup_sel_tot = 0; + MEM_SAFE_FREE(vwsel.defgroup_sel); + } + } + + /* Generate the weight data using the selection. */ + GPUBatch *batch = DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(me, &vwsel); + + DRW_vweight_selection_clear(&vwsel); + + return batch; } GPUBatch *DRW_cache_mesh_surface_vert_colors_get(Object *ob) diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 08c93010700..edd1362bf9b 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -135,7 +135,7 @@ struct GPUBatch *DRW_cache_mesh_wire_outline_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_edge_detection_get(struct Object *ob, bool *r_is_manifold); struct GPUBatch *DRW_cache_mesh_surface_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_loose_edges_get(struct Object *ob); -struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob, struct ToolSettings *ts, bool paint_mode); struct GPUBatch *DRW_cache_mesh_surface_vert_colors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_verts_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_edges_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index d601bfc3a3e..444d5aeb12d 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -96,8 +96,29 @@ struct GPUBatch *DRW_lattice_batch_cache_get_all_edges(struct Lattice *lt, bool struct GPUBatch *DRW_lattice_batch_cache_get_all_verts(struct Lattice *lt); struct GPUBatch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt); -/* Mesh */ +/* Vertex Group Selection and display options */ +typedef struct VertexWeightSelection { + int defgroup_active; + int defgroup_tot; + + short flags; + char alert_mode; + + /* Set of all selected bones for Multipaint. */ + int defgroup_sel_tot; + bool *defgroup_sel; +} VertexWeightSelection; + +enum { + VWEIGHT_MULTIPAINT = (1 << 0), + VWEIGHT_AUTO_NORMALIZE = (1 << 1), +}; +void DRW_vweight_selection_clear(struct VertexWeightSelection *sel); +void DRW_vweight_selection_copy(struct VertexWeightSelection *sel, const struct VertexWeightSelection *src); +bool DRW_vweight_selection_compare(const struct VertexWeightSelection *a, const struct VertexWeightSelection *b); + +/* Mesh */ struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded( struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); @@ -109,7 +130,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_weight_overlay_verts(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_all_edges(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_all_triangles(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals(struct Mesh *me); -struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me, int defgroup); +struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(struct Mesh *me, const struct VertexWeightSelection *vwsel); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_vert_colors(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_id(struct Mesh *me, bool use_hide, uint select_id_offset); struct GPUBatch *DRW_mesh_batch_cache_get_triangles_with_select_mask(struct Mesh *me, bool use_hide); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 75aaac23f75..8fef7675587 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -34,6 +34,7 @@ #include "BLI_utildefines.h" #include "BLI_math_vector.h" #include "BLI_math_bits.h" +#include "BLI_math_color.h" #include "BLI_string.h" #include "BLI_alloca.h" #include "BLI_edgehash.h" @@ -1101,13 +1102,67 @@ static void rgb_from_weight(float r_rgb[3], const float weight) } } +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 */ -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; if (vweight == NULL) { - if (defgroup == -1) { + if (vwsel->defgroup_active == -1) { goto fallback; } @@ -1125,13 +1180,7 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); BM_ITER_MESH_INDEX(eve, &viter, bm, BM_VERT, i) { const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); - float weight = defvert_find_weight(dvert, defgroup); - if (U.flag & USER_CUSTOM_RANGE) { - BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); - } - else { - rgb_from_weight(vweight[i], weight); - } + evaluate_vertex_weight(vweight[i], dvert, vwsel); } } else { @@ -1141,23 +1190,26 @@ static void mesh_render_data_ensure_vert_weight_color(MeshRenderData *rdata, con vweight = rdata->vert_weight_color = MEM_mallocN(sizeof(*vweight) * rdata->vert_len, __func__); for (int i = 0; i < rdata->vert_len; i++) { - float weight = defvert_find_weight(&rdata->dvert[i], defgroup); - if (U.flag & USER_CUSTOM_RANGE) { - BKE_colorband_evaluate(&U.coba_weight, weight, vweight[i]); - } - else { - rgb_from_weight(vweight[i], weight); - } + evaluate_vertex_weight(vweight[i], &rdata->dvert[i], vwsel); } } } return; 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++) { - vweight[i][2] = 0.5f; + copy_v3_v3(vweight[i], error_color); } } @@ -1537,6 +1589,47 @@ static void add_overlay_loose_vert( /** \} */ +/* ---------------------------------------------------------------------- */ + +/** \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)); +} + +/** \} */ /* ---------------------------------------------------------------------- */ @@ -1646,7 +1739,8 @@ typedef struct MeshBatchCache { int vert_len; int mat_len; bool is_editmode; - int vertex_group_index; + + VertexWeightSelection vertex_weight_selection; /* XXX, only keep for as long as sculpt mode uses shaded drawing. */ bool is_sculpt_points_tag; @@ -1722,7 +1816,8 @@ static void mesh_batch_cache_init(Mesh *me) cache->is_maybe_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) @@ -1734,13 +1829,13 @@ static MeshBatchCache *mesh_batch_cache_get(Mesh *me) 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) { - MeshBatchCache *cache = mesh_batch_cache_get(me); - if (cache->vertex_group_index != defgroup) { - cache->is_dirty = true; + if (!DRW_vweight_selection_compare(&cache->vertex_weight_selection, vwsel)) { + GPU_BATCH_DISCARD_SAFE(cache->triangles_with_weights); + + DRW_vweight_selection_clear(&cache->vertex_weight_selection); } - return mesh_batch_cache_get(me); } static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) @@ -1918,6 +2013,7 @@ static void mesh_batch_cache_clear(Mesh *me) GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); + DRW_vweight_selection_clear(&cache->vertex_weight_selection); } void DRW_mesh_batch_cache_free(Mesh *me) @@ -2674,7 +2770,7 @@ static GPUVertBuf *mesh_create_verts_select_id( } static GPUVertBuf *mesh_create_tri_weights( - MeshRenderData *rdata, bool use_hide, int defgroup) + MeshRenderData *rdata, bool use_hide, const VertexWeightSelection *vwsel) { BLI_assert( rdata->types & @@ -2697,7 +2793,7 @@ static GPUVertBuf *mesh_create_tri_weights( int vbo_len_used = 0; 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; if (rdata->edit_bmesh) { @@ -3866,9 +3962,11 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges_with_normals(Mesh *me) 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) { const bool use_hide = (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) != 0; @@ -3877,8 +3975,9 @@ GPUBatch *DRW_mesh_batch_cache_get_triangles_with_normals_and_weights(Mesh *me, MeshRenderData *rdata = mesh_render_data_create(me, datatype); cache->triangles_with_weights = GPU_batch_create_ex( - GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, defgroup), NULL, GPU_BATCH_OWNS_VBO); - cache->vertex_group_index = defgroup; + GPU_PRIM_TRIS, mesh_create_tri_weights(rdata, use_hide, vwsel), NULL, GPU_BATCH_OWNS_VBO); + + DRW_vweight_selection_copy(&cache->vertex_weight_selection, vwsel); GPUVertBuf *vbo_tris = use_hide ? mesh_create_tri_pos_and_normals_visible_only(rdata) : diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index 4cf99ef3c1e..3a2ad27bfa9 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -594,7 +594,7 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) } if (do_show_weight) { - geom = DRW_cache_mesh_surface_weights_get(ob); + geom = DRW_cache_mesh_surface_weights_get(ob, tsettings, false); DRW_shgroup_call_add(stl->g_data->fvcolor_shgrp, geom, ob->obmat); } diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c index c4608dfd397..3826e8af8fa 100644 --- a/source/blender/draw/modes/paint_weight_mode.c +++ b/source/blender/draw/modes/paint_weight_mode.c @@ -183,7 +183,7 @@ static void PAINT_WEIGHT_cache_populate(void *vedata, Object *ob) struct GPUBatch *geom; if (use_surface) { - geom = DRW_cache_mesh_surface_weights_get(ob); + geom = DRW_cache_mesh_surface_weights_get(ob, draw_ctx->scene->toolsettings, true); DRW_shgroup_call_add(stl->g_data->fweights_shgrp, geom, ob->obmat); } diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 53c5da243fe..eaf212eabfe 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -3598,6 +3598,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "editflag", ME_EDIT_MIRROR_X); RNA_def_property_ui_text(prop, "X Mirror", "X Axis mirror editing"); + RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); #if 0 prop = RNA_def_property(srna, "use_mirror_y", PROP_BOOLEAN, PROP_NONE); |