diff options
12 files changed, 878 insertions, 611 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 4bd0046a48a..9ce994adbc0 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -36,6 +36,7 @@ struct ListBase; struct ModifierData; struct ParticleSystem; struct PTCacheEdit; +struct SpaceImage; struct Curve; struct Lattice; @@ -156,6 +157,20 @@ void DRW_mesh_batch_cache_get_wireframes_face_texbuf( void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me); +enum { + UVEDIT_EDGES = (1 << 0), + UVEDIT_DATA = (1 << 1), + UVEDIT_FACEDOTS = (1 << 2), + UVEDIT_FACES = (1 << 3), + UVEDIT_STRETCH_ANGLE = (1 << 4), + UVEDIT_STRETCH_AREA = (1 << 5), + UVEDIT_SYNC_SEL = (1 << 6), +}; + +void DRW_mesh_cache_uvedit( + struct Object *me, struct SpaceImage *sima, struct Scene *scene, uchar state, + struct GPUBatch **faces, struct GPUBatch **edges, struct GPUBatch **verts, struct GPUBatch **facedots); + /* Edit mesh bitflags (is this the right place?) */ enum { diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 6a324aa078f..9d3543a0d20 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_buffer.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" #include "BLI_math_bits.h" @@ -42,6 +43,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_space_types.h" #include "BKE_customdata.h" #include "BKE_deform.h" @@ -60,6 +62,10 @@ #include "DRW_render.h" +#include "ED_image.h" +#include "ED_mesh.h" +#include "ED_uvedit.h" + #include "draw_cache_impl.h" /* own include */ static void mesh_batch_cache_clear(Mesh *me); @@ -1672,6 +1678,24 @@ typedef struct MeshBatchCache { GPUBatch *overlay_weight_verts; GPUBatch *overlay_paint_edges; + /* 2D/UV edit */ + GPUVertBuf *edituv_pos; + GPUVertBuf *edituv_area; + GPUVertBuf *edituv_angle; + GPUVertBuf *edituv_data; + + GPUIndexBuf *edituv_visible_faces; + GPUIndexBuf *edituv_visible_edges; + + GPUBatch *edituv_faces_strech_area; + GPUBatch *edituv_faces_strech_angle; + GPUBatch *edituv_faces; + GPUBatch *edituv_edges; + GPUBatch *edituv_verts; + GPUBatch *edituv_facedots; + + char edituv_state; + /* arrays of bool uniform names (and value) that will be use to * set srgb conversion for auto attribs.*/ char *auto_layer_names; @@ -1807,6 +1831,26 @@ static void mesh_batch_cache_discard_shaded_tri(MeshBatchCache *cache) MEM_SAFE_FREE(cache->auto_layer_is_srgb); } +static void mesh_batch_cache_discard_uvedit(MeshBatchCache *cache) +{ + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_pos); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_area); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_angle); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_data); + + GPU_INDEXBUF_DISCARD_SAFE(cache->edituv_visible_faces); + GPU_INDEXBUF_DISCARD_SAFE(cache->edituv_visible_edges); + + GPU_BATCH_DISCARD_SAFE(cache->edituv_faces_strech_area); + GPU_BATCH_DISCARD_SAFE(cache->edituv_faces_strech_angle); + GPU_BATCH_DISCARD_SAFE(cache->edituv_faces); + GPU_BATCH_DISCARD_SAFE(cache->edituv_edges); + GPU_BATCH_DISCARD_SAFE(cache->edituv_verts); + GPU_BATCH_DISCARD_SAFE(cache->edituv_facedots); + + cache->edituv_state = 0; +} + void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) { MeshBatchCache *cache = me->runtime.batch_cache; @@ -1833,12 +1877,15 @@ void DRW_mesh_batch_cache_dirty_tag(Mesh *me, int mode) GPU_BATCH_DISCARD_SAFE(cache->facedot_with_select_id); GPU_BATCH_DISCARD_SAFE(cache->edges_with_select_id); GPU_BATCH_DISCARD_SAFE(cache->verts_with_select_id); + /* Because visible UVs depends on edit mode selection, discard everything. */ + mesh_batch_cache_discard_uvedit(cache); break; case BKE_MESH_BATCH_DIRTY_ALL: cache->is_dirty = true; break; case BKE_MESH_BATCH_DIRTY_SHADING: mesh_batch_cache_discard_shaded_tri(cache); + mesh_batch_cache_discard_uvedit(cache); break; case BKE_MESH_BATCH_DIRTY_SCULPT_COORDS: cache->is_sculpt_points_tag = true; @@ -1952,6 +1999,8 @@ static void mesh_batch_cache_clear(Mesh *me) mesh_batch_cache_discard_shaded_tri(cache); + mesh_batch_cache_discard_uvedit(cache); + if (cache->texpaint_triangles) { for (int i = 0; i < cache->mat_len; ++i) { GPU_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); @@ -4528,4 +4577,416 @@ void DRW_mesh_cache_sculpt_coords_ensure(Mesh *me) } } +static uchar mesh_batch_cache_validate_edituvs(MeshBatchCache *cache, uchar state) +{ + if ((cache->edituv_state & UVEDIT_SYNC_SEL) != (state & UVEDIT_SYNC_SEL)) { + mesh_batch_cache_discard_uvedit(cache); + return state; + } + else { + return ((cache->edituv_state & state) ^ state); + } +} + +/* Compute 3D & 2D areas and their sum. */ +BLI_INLINE void edit_uv_preprocess_stretch_area( + float (*tf_uv)[2], BMFace *efa, const float asp[2], const int cd_loop_uv_offset, uint fidx, + float *totarea, float *totuvarea, float (*faces_areas)[2]) +{ + BMLoop *l; + BMIter liter; + int i; + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + mul_v2_v2v2(tf_uv[i], luv->uv, asp); + } + faces_areas[fidx][0] = BM_face_calc_area(efa); + faces_areas[fidx][1] = area_poly_v2(tf_uv, efa->len); + + *totarea += faces_areas[fidx][0]; + *totuvarea += faces_areas[fidx][1]; +} + +BLI_INLINE float edit_uv_get_stretch_area(float area, float uvarea) +{ + if (area < FLT_EPSILON || uvarea < FLT_EPSILON) { + return 1.0f; + } + else if (area > uvarea) { + return 1.0f - (uvarea / area); + } + else { + return 1.0f - (area / uvarea); + } +} + +/* Compute face's normalized contour vectors. */ +BLI_INLINE void edit_uv_preprocess_stretch_angle( + float (*auv)[2], float (*av)[3], const int cd_loop_uv_offset, BMFace *efa, float asp[2]) +{ + BMLoop *l; + BMIter liter; + int i; + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset); + + sub_v2_v2v2(auv[i], luv_prev->uv, luv->uv); + mul_v2_v2(auv[i], asp); + normalize_v2(auv[i]); + + sub_v3_v3v3(av[i], l->prev->v->co, l->v->co); + normalize_v3(av[i]); + } +} + +BLI_INLINE float edit_uv_get_loop_stretch_angle( + const float auv0[2], const float auv1[2], const float av0[3], const float av1[3]) +{ + float uvang = angle_normalized_v2v2(auv0, auv1); + float ang = angle_normalized_v3v3(av0, av1); + float stretch = fabsf(uvang - ang) / (float)M_PI; + return 1.0f - pow2f(1.0f - stretch); +} + +#define VERTEX_SELECT (1 << 0) +#define VERTEX_PINNED (1 << 1) +#define FACE_SELECT (1 << 2) +#define FACE_ACTIVE (1 << 3) +#define EDGE_SELECT (1 << 4) + +BLI_INLINE uchar edit_uv_get_face_flag(BMFace *efa, BMFace *efa_act, const int cd_loop_uv_offset, Scene *scene) +{ + uchar flag = 0; + flag |= uvedit_face_select_test(scene, efa, cd_loop_uv_offset) ? FACE_SELECT : 0; + flag |= (efa == efa_act) ? FACE_ACTIVE : 0; + return flag; +} + +BLI_INLINE uchar edit_uv_get_loop_flag(BMLoop *l, const int cd_loop_uv_offset, Scene *scene) +{ + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uchar flag = 0; + flag |= uvedit_uv_select_test(scene, l, cd_loop_uv_offset) ? VERTEX_SELECT : 0; + flag |= uvedit_edge_select_test(scene, l, cd_loop_uv_offset) ? EDGE_SELECT : 0; + flag |= (luv->flag & MLOOPUV_PINNED) ? VERTEX_PINNED : 0; + return flag; +} + +static struct EditUVFormatIndex { + uint uvs, area, angle, flag, fdots_uvs, fdots_flag; +} uv_attr_id = {0}; + +static void uvedit_fill_buffer_data( + Object *ob, struct SpaceImage *sima, Scene *scene, uchar state, MeshBatchCache *cache, + GPUIndexBufBuilder *elb_faces, GPUIndexBufBuilder *elb_edges, GPUVertBuf **facedots_vbo) +{ + Mesh *me = ob->data; + BMEditMesh *embm = me->edit_btmesh; + BMesh *bm = embm->bm; + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + MLoopUV *luv; + uint vidx, fidx, i; + float (*faces_areas)[2] = NULL; + float asp[2]; + float totarea = 0.0f, totuvarea = 0.0f; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + Image *ima = sima->image; + BMFace *efa_act = EDBM_uv_active_face_get(embm, false, false); /* will be set to NULL if hidden */ + + if (state & (UVEDIT_STRETCH_AREA | UVEDIT_STRETCH_ANGLE)) { + ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]); + } + + BLI_buffer_declare_static(vec3f, vec3_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + BLI_buffer_declare_static(vec2f, vec2_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); + + if (state & UVEDIT_STRETCH_AREA) { + faces_areas = MEM_mallocN(sizeof(float) * 2 * bm->totface, "EDITUV faces areas"); + } + + /* Preprocess */ + fidx = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + /* Tag hidden faces */ + BM_elem_flag_set(efa, BM_ELEM_TAG, uvedit_face_visible_test(scene, ob, ima, efa)); + + if ((state & UVEDIT_STRETCH_AREA) && + BM_elem_flag_test(efa, BM_ELEM_TAG)) + { + const int efa_len = efa->len; + float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len); + edit_uv_preprocess_stretch_area(tf_uv, efa, asp, cd_loop_uv_offset, fidx++, + &totarea, &totuvarea, faces_areas); + } + } + + vidx = 0; + fidx = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + const int efa_len = efa->len; + float fdot[2] = {0.0f, 0.0f}; + float (*av)[3], (*auv)[2]; + ushort area_stretch; + /* Skip hidden faces. */ + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + uchar face_flag = edit_uv_get_face_flag(efa, efa_act, cd_loop_uv_offset, scene); + /* Face preprocess */ + if (state & UVEDIT_STRETCH_AREA) { + area_stretch = edit_uv_get_stretch_area(faces_areas[fidx][0] / totarea, + faces_areas[fidx][1] / totuvarea) * 65534.0f; + } + if (state & UVEDIT_STRETCH_ANGLE) { + av = (float (*)[3])BLI_buffer_reinit_data(&vec3_buf, vec3f, efa_len); + auv = (float (*)[2])BLI_buffer_reinit_data(&vec2_buf, vec2f, efa_len); + edit_uv_preprocess_stretch_angle(auv, av, cd_loop_uv_offset, efa, asp); + } + + BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + uchar flag = face_flag | edit_uv_get_loop_flag(l, cd_loop_uv_offset, scene); + + if (state & UVEDIT_STRETCH_AREA) { + GPU_vertbuf_attr_set(cache->edituv_area, uv_attr_id.area, vidx, &area_stretch); + } + if (state & UVEDIT_STRETCH_ANGLE) { + ushort angle = 65534.0f * edit_uv_get_loop_stretch_angle(auv[i], auv[(i + 1) % efa_len], + av[i], av[(i + 1) % efa_len]); + GPU_vertbuf_attr_set(cache->edituv_angle, uv_attr_id.angle, vidx, &angle); + } + if (state & UVEDIT_EDGES) { + GPU_vertbuf_attr_set(cache->edituv_pos, uv_attr_id.uvs, vidx, luv->uv); + } + if (state & UVEDIT_DATA) { + GPU_vertbuf_attr_set(cache->edituv_data, uv_attr_id.flag, vidx, &flag); + } + if (state & UVEDIT_FACES) { + GPU_indexbuf_add_generic_vert(elb_faces, vidx); + } + if (state & UVEDIT_EDGES) { + GPU_indexbuf_add_generic_vert(elb_edges, vidx); + } + + if (state & UVEDIT_FACEDOTS) { + add_v2_v2(fdot, luv->uv); + } + vidx++; + } + + if (state & UVEDIT_FACES) { + GPU_indexbuf_add_primitive_restart(elb_faces); + } + if (state & UVEDIT_EDGES) { + GPU_indexbuf_add_primitive_restart(elb_edges); + } + + if (state & UVEDIT_FACEDOTS) { + mul_v2_fl(fdot, 1.0f / (float)efa->len); + GPU_vertbuf_attr_set(*facedots_vbo, uv_attr_id.fdots_uvs, fidx, fdot); + GPU_vertbuf_attr_set(*facedots_vbo, uv_attr_id.fdots_flag, fidx, &face_flag); + } + fidx++; + } + + if (faces_areas) { + MEM_freeN(faces_areas); + } + + BLI_buffer_free(&vec3_buf); + BLI_buffer_free(&vec2_buf); + + if (vidx == 0) { + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_area); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_angle); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_pos); + GPU_VERTBUF_DISCARD_SAFE(cache->edituv_data); + GPU_VERTBUF_DISCARD_SAFE(*facedots_vbo); + } + + if (vidx < bm->totloop) { + if (cache->edituv_area && (state & UVEDIT_STRETCH_AREA)) { + GPU_vertbuf_data_resize(cache->edituv_area, vidx); + } + if (cache->edituv_angle && (state & UVEDIT_STRETCH_ANGLE)) { + GPU_vertbuf_data_resize(cache->edituv_angle, vidx); + } + if (cache->edituv_pos && (state & UVEDIT_EDGES)) { + GPU_vertbuf_data_resize(cache->edituv_pos, vidx); + } + if (cache->edituv_data && (state & UVEDIT_DATA)) { + GPU_vertbuf_data_resize(cache->edituv_data, vidx); + } + } + if (fidx < bm->totface) { + if (*facedots_vbo) { + GPU_vertbuf_data_resize(*facedots_vbo, fidx); + } + } +} + +static void mesh_batch_cache_create_uvedit_buffers( + Object *ob, struct SpaceImage *sima, Scene *scene, MeshBatchCache *cache, uchar state) +{ + GPUVertBuf *facedots_vbo = NULL; + + if (state == 0) { + return; + } + + Mesh *me = ob->data; + BMEditMesh *embm = me->edit_btmesh; + BMesh *bm = embm->bm; + + static GPUVertFormat format_pos = { 0 }; + static GPUVertFormat format_area = { 0 }; + static GPUVertFormat format_angle = { 0 }; + static GPUVertFormat format_flag = { 0 }; + static GPUVertFormat format_facedots = { 0 }; + + if (format_pos.attr_len == 0) { + uv_attr_id.uvs = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uv_attr_id.area = GPU_vertformat_attr_add(&format_area, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + uv_attr_id.angle = GPU_vertformat_attr_add(&format_angle, "stretch", GPU_COMP_U16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + uv_attr_id.flag = GPU_vertformat_attr_add(&format_flag, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT); + + uv_attr_id.fdots_uvs = GPU_vertformat_attr_add(&format_facedots, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uv_attr_id.fdots_flag = GPU_vertformat_attr_add(&format_facedots, "flag", GPU_COMP_U8, 1, GPU_FETCH_INT); + } + + const uint vert_len = bm->totloop; + const uint idx_len = bm->totloop + bm->totface; + const uint face_len = bm->totface; + + if (state & UVEDIT_EDGES) { + cache->edituv_pos = GPU_vertbuf_create_with_format(&format_pos); + GPU_vertbuf_data_alloc(cache->edituv_pos, vert_len); + } + if (state & UVEDIT_DATA) { + cache->edituv_data = GPU_vertbuf_create_with_format(&format_flag); + GPU_vertbuf_data_alloc(cache->edituv_data, vert_len); + } + if (state & UVEDIT_STRETCH_AREA) { + cache->edituv_area = GPU_vertbuf_create_with_format(&format_area); + GPU_vertbuf_data_alloc(cache->edituv_area, vert_len); + } + if (state & UVEDIT_STRETCH_ANGLE) { + cache->edituv_angle = GPU_vertbuf_create_with_format(&format_angle); + GPU_vertbuf_data_alloc(cache->edituv_angle, vert_len); + } + if (state & UVEDIT_FACEDOTS) { + facedots_vbo = GPU_vertbuf_create_with_format(&format_facedots); + GPU_vertbuf_data_alloc(facedots_vbo, face_len); + } + + /* NOTE: we could use the same index buffer for both primitive type (it's the same indices) + * but since GPU_PRIM_LINE_LOOP does not exist in vulkan, make it future proof. */ + GPUIndexBufBuilder elb_faces, elb_edges; + if (state & UVEDIT_EDGES) { + GPU_indexbuf_init_ex(&elb_edges, GPU_PRIM_LINE_LOOP, idx_len, vert_len, true); + } + if (state & UVEDIT_FACES) { + GPU_indexbuf_init_ex(&elb_faces, GPU_PRIM_TRI_FAN, idx_len, vert_len, true); + } + + uvedit_fill_buffer_data(ob, sima, scene, state, cache, &elb_faces, &elb_edges, &facedots_vbo); + + if (state & UVEDIT_EDGES) { + cache->edituv_visible_edges = GPU_indexbuf_build(&elb_edges); + } + if (state & UVEDIT_FACES) { + cache->edituv_visible_faces = GPU_indexbuf_build(&elb_faces); + } + if ((state & UVEDIT_FACEDOTS) && facedots_vbo) { + cache->edituv_facedots = GPU_batch_create_ex(GPU_PRIM_POINTS, facedots_vbo, NULL, GPU_BATCH_OWNS_VBO); + } + + cache->edituv_state |= state; +} + +void DRW_mesh_cache_uvedit( + Object *ob, struct SpaceImage *sima, Scene *scene, uchar state, + GPUBatch **faces, GPUBatch **edges, GPUBatch **verts, GPUBatch **facedots) +{ + Mesh *me = ob->data; + MeshBatchCache *cache = mesh_batch_cache_get(me); + + uchar missing_state = mesh_batch_cache_validate_edituvs(cache, state); + + mesh_batch_cache_create_uvedit_buffers(ob, sima, scene, cache, missing_state); + + /* Bail out if there is nothing to draw. */ + if (cache->edituv_data == NULL) { + *faces = *edges = *verts = *facedots = NULL; + return; + } + + /* Faces */ + if (state & UVEDIT_STRETCH_AREA) { + if (cache->edituv_faces_strech_area == NULL) { + cache->edituv_faces_strech_area = GPU_batch_create(GPU_PRIM_TRI_FAN, + cache->edituv_pos, + cache->edituv_visible_faces); + GPU_batch_vertbuf_add_ex(cache->edituv_faces_strech_area, + cache->edituv_area, false); + } + *faces = cache->edituv_faces_strech_area; + } + else if (state & UVEDIT_STRETCH_ANGLE) { + if (cache->edituv_faces_strech_angle == NULL) { + cache->edituv_faces_strech_angle = GPU_batch_create(GPU_PRIM_TRI_FAN, + cache->edituv_pos, + cache->edituv_visible_faces); + GPU_batch_vertbuf_add_ex(cache->edituv_faces_strech_angle, + cache->edituv_angle, false); + } + *faces = cache->edituv_faces_strech_angle; + } + else if (state & UVEDIT_FACES) { + if (cache->edituv_faces == NULL) { + cache->edituv_faces = GPU_batch_create(GPU_PRIM_TRI_FAN, + cache->edituv_pos, + cache->edituv_visible_faces); + GPU_batch_vertbuf_add_ex(cache->edituv_faces, + cache->edituv_data, false); + } + *faces = cache->edituv_faces; + } + else { + *faces = NULL; + } + + { + if (cache->edituv_edges == NULL) { + cache->edituv_edges = GPU_batch_create(GPU_PRIM_LINE_LOOP, + cache->edituv_pos, + cache->edituv_visible_edges); + GPU_batch_vertbuf_add_ex(cache->edituv_edges, + cache->edituv_data, false); + } + *edges = cache->edituv_edges; + } + + { + if (cache->edituv_verts == NULL) { + cache->edituv_verts = GPU_batch_create(GPU_PRIM_POINTS, + cache->edituv_pos, + NULL); + GPU_batch_vertbuf_add_ex(cache->edituv_verts, + cache->edituv_data, false); + } + *verts = cache->edituv_verts; + } + + if (state & UVEDIT_FACEDOTS) { + *facedots = cache->edituv_facedots; + } + else { + *facedots = NULL; + } +} + /** \} */ diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 57fed0b860f..ee3afdd5772 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -43,6 +43,8 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "../../draw/intern/draw_cache_impl.h" + #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_buffer.h" @@ -65,6 +67,7 @@ #include "GPU_immediate_util.h" #include "GPU_matrix.h" #include "GPU_state.h" +#include "GPU_draw.h" #include "ED_image.h" #include "ED_mesh.h" @@ -184,211 +187,6 @@ static void draw_uvs_shadow(Object *obedit) immUnbindProgram(); } -static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, Object *obedit, BMEditMesh *em, const BMFace *efa_act) -{ - BMesh *bm = em->bm; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - Image *ima = sima->image; - float aspx, aspy, col[4]; - int i; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - BLI_buffer_declare_static(vec2f, tf_uvorig_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - - ED_space_image_get_uv_aspect(sima, &aspx, &aspy); - - switch (sima->dt_uvstretch) { - case SI_UVDT_STRETCH_AREA: - { - float totarea = 0.0f, totuvarea = 0.0f, areadiff, uvarea, area; - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(tf_uvorig[i], luv->uv); - } - - uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len); - - totarea += BM_face_calc_area(efa); - totuvarea += area_poly_v2(tf_uv, efa->len); - - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - } - else { - if (efa == efa_act) { - efa_act = NULL; - } - BM_elem_flag_disable(efa, BM_ELEM_TAG); - } - } - - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - if (totarea < FLT_EPSILON || totuvarea < FLT_EPSILON) { - col[0] = 1.0; - col[1] = col[2] = 0.0; - - immUniformColor3fv(col); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - immBegin(GPU_PRIM_TRI_FAN, efa->len); - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } - - immEnd(); - } - } - } - else { - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); - - area = BM_face_calc_area(efa) / totarea; - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(tf_uvorig[i], luv->uv); - } - - uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len); - - uvarea = area_poly_v2(tf_uv, efa->len) / totuvarea; - - if (area < FLT_EPSILON || uvarea < FLT_EPSILON) - areadiff = 1.0f; - else if (area > uvarea) - areadiff = 1.0f - (uvarea / area); - else - areadiff = 1.0f - (area / uvarea); - - BKE_defvert_weight_to_rgb(col, areadiff); - immUniformColor3fv(col); - - /* TODO: use editmesh tessface */ - immBegin(GPU_PRIM_TRI_FAN, efa->len); - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } - - immEnd(); - } - } - } - - immUnbindProgram(); - - break; - } - case SI_UVDT_STRETCH_ANGLE: - { - float a; - - BLI_buffer_declare_static(float, uvang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - BLI_buffer_declare_static(float, ang_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - BLI_buffer_declare_static(vec3f, av_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - BLI_buffer_declare_static(vec2f, auv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); - - col[3] = 0.5f; /* hard coded alpha, not that nice */ - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - const int efa_len = efa->len; - float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len); - float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len); - float *uvang = BLI_buffer_reinit_data(&uvang_buf, float, efa_len); - float *ang = BLI_buffer_reinit_data(&ang_buf, float, efa_len); - float (*av)[3] = (float (*)[3])BLI_buffer_reinit_data(&av_buf, vec3f, efa_len); - float (*auv)[2] = (float (*)[2])BLI_buffer_reinit_data(&auv_buf, vec2f, efa_len); - int j; - - BM_elem_flag_enable(efa, BM_ELEM_TAG); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(tf_uvorig[i], luv->uv); - } - - uv_poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa_len); - - j = efa_len - 1; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - sub_v2_v2v2(auv[i], tf_uv[j], tf_uv[i]); normalize_v2(auv[i]); - sub_v3_v3v3(av[i], l->prev->v->co, l->v->co); normalize_v3(av[i]); - j = i; - } - - for (i = 0; i < efa_len; i++) { -#if 0 - /* Simple but slow, better reuse normalized vectors - * (Not ported to bmesh, copied for reference) */ - uvang1 = RAD2DEG(angle_v2v2v2(tf_uv[3], tf_uv[0], tf_uv[1])); - ang1 = RAD2DEG(angle_v3v3v3(efa->v4->co, efa->v1->co, efa->v2->co)); -#endif - uvang[i] = angle_normalized_v2v2(auv[i], auv[(i + 1) % efa_len]); - ang[i] = angle_normalized_v3v3(av[i], av[(i + 1) % efa_len]); - } - - /* TODO: use editmesh tessface */ - immBegin(GPU_PRIM_TRI_FAN, efa->len); - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - a = fabsf(uvang[i] - ang[i]) / (float)M_PI; - BKE_defvert_weight_to_rgb(col, 1.0f - pow2f(1.0f - a)); - immAttrib3fv(color, col); - immVertex2fv(pos, luv->uv); - } - immEnd(); - } - else { - if (efa == efa_act) - efa_act = NULL; - BM_elem_flag_disable(efa, BM_ELEM_TAG); - } - } - - immUnbindProgram(); - - BLI_buffer_free(&uvang_buf); - BLI_buffer_free(&ang_buf); - BLI_buffer_free(&av_buf); - BLI_buffer_free(&auv_buf); - - break; - } - } - - BLI_buffer_free(&tf_uv_buf); - BLI_buffer_free(&tf_uvorig_buf); -} - static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos) { BMIter iter, liter; @@ -467,459 +265,218 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob) } } -static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const int cd_loop_uv_offset, unsigned int pos) +static uchar get_state(SpaceImage *sima, Scene *scene) { - unsigned int i = *r_loop_index; - BMFace *f = em->looptris[i][0]->f; - do { - unsigned int j; - for (j = 0; j < 3; j++) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(em->looptris[i][j], cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); + ToolSettings *ts = scene->toolsettings; + int drawfaces = draw_uvs_face_check(scene); + const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0; + uchar state = UVEDIT_EDGES | UVEDIT_DATA; + + if (drawfaces) { + state |= UVEDIT_FACEDOTS; + } + if (draw_stretch || !(sima->flag & SI_NO_DRAWFACES)) { + state |= UVEDIT_FACES; + + if (draw_stretch) { + if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) { + state |= UVEDIT_STRETCH_AREA; + } + else { + state |= UVEDIT_STRETCH_ANGLE; + } } - i++; - } while (i != em->tottri && (f == em->looptris[i][0]->f)); - *r_loop_index = i - 1; + } + if (ts->uv_flag & UV_SYNC_SELECTION) { + state |= UVEDIT_SYNC_SEL; + } + return state; } /* draws uv's in the image space */ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph *depsgraph) { - ToolSettings *ts; - Mesh *me = obedit->data; - BMEditMesh *em = me->edit_btmesh; - BMesh *bm = em->bm; - BMFace *efa, *efa_act; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - float col1[4], col2[4]; - float pointsize; - int drawfaces, interpedges; - Image *ima = sima->image; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - unsigned int pos, color; - - efa_act = EDBM_uv_active_face_get(em, false, false); /* will be set to NULL if hidden */ - ts = scene->toolsettings; - - drawfaces = draw_uvs_face_check(scene); - if (ts->uv_flag & UV_SYNC_SELECTION) - interpedges = (ts->selectmode & SCE_SELECT_VERTEX); - else - interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX); - - /* 1. draw shadow mesh */ + GPUBatch *faces, *edges, *verts, *facedots; + Object *eval_ob = DEG_get_evaluated_object(depsgraph, obedit); + ToolSettings *ts = scene->toolsettings; + float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f}; if (sima->flag & SI_DRAWSHADOW) { - Object *ob_cage_eval = DEG_get_evaluated_object(depsgraph, obedit); /* XXX TODO: Need to check if shadow mesh is different than original mesh. */ - bool is_cage_like_final_meshes = (ob_cage_eval == obedit); + bool is_cage_like_final_meshes = true; /* When sync selection is enabled, all faces are drawn (except for hidden) * so if cage is the same as the final, there is no point in drawing this. */ - if (((ts->uv_flag & UV_SYNC_SELECTION) == 0) || is_cage_like_final_meshes) { - draw_uvs_shadow(ob_cage_eval); + if (!((ts->uv_flag & UV_SYNC_SELECTION) && is_cage_like_final_meshes)) { + draw_uvs_shadow(eval_ob); } } - if (bm->totloop == 0) { - return; - } + uchar state = get_state(sima, scene); - /* 2. draw colored faces */ + DRW_mesh_cache_uvedit( + eval_ob, sima, scene, state, + &faces, &edges, &verts, &facedots); - if (sima->flag & SI_DRAW_STRETCH) { - draw_uvs_stretch(sima, scene, obedit, em, efa_act); + bool interpedges; + bool do_elem_order_fix = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); + bool do_selected_edges = ((sima->flag & SI_NO_DRAWEDGES) == 0); + bool draw_stretch = (state & (UVEDIT_STRETCH_AREA | UVEDIT_STRETCH_ANGLE)) != 0; + if (ts->uv_flag & UV_SYNC_SELECTION) { + interpedges = (ts->selectmode & SCE_SELECT_VERTEX) != 0; } else { - unsigned int tri_count = 0; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, obedit, ima, efa)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - tri_count += efa->len - 2; - } - else { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - } - } - - if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { - /* draw transparent faces */ - UI_GetThemeColor4fv(TH_FACE, col1); - UI_GetThemeColor4fv(TH_FACE_SELECT, col2); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - GPUVertFormat *format = immVertexFormat(); - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - - GPUBatch *face_batch = immBeginBatch(GPU_PRIM_TRIS, tri_count * 3); - for (unsigned int i = 0; i < em->tottri; i++) { - efa = em->looptris[i][0]->f; - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - const bool is_select = uvedit_face_select_test(scene, efa, cd_loop_uv_offset); - - if (efa == efa_act) { - /* only once */ - float tmp_col[4]; - UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, tmp_col); - immAttrib4fv(color, tmp_col); - } - else { - immAttrib4fv(color, is_select ? col2 : col1); - } - - draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); - } - } - immEnd(); - - /* XXX performance: we should not create and throw away result. */ - GPU_batch_draw(face_batch); - GPU_batch_program_use_end(face_batch); - GPU_batch_discard(face_batch); - - immUnbindProgram(); - - GPU_blend(false); - } - else { - if (efa_act && !uvedit_face_visible_test(scene, obedit, ima, efa_act)) { - efa_act = NULL; - } - } - } - - /* 3. draw active face stippled */ - /* (removed during OpenGL upgrade, reimplement if needed) */ - - /* 4. draw edges */ - - if (sima->flag & SI_SMOOTH_UV) { - GPU_line_smooth(true); - GPU_blend(true); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + interpedges = (ts->uv_selectmode == UV_SELECT_VERTEX); } - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - switch (sima->dt_uv) { - case SI_UVDT_DASH: - { - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + if (faces) { + GPU_batch_program_set_builtin(faces, (draw_stretch) + ? GPU_SHADER_2D_UV_FACES_STRETCH + : GPU_SHADER_2D_UV_FACES); - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - - immUniform1i("colors_len", 2); /* "advanced" mode */ - immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2); - immUniform1f("dash_width", 4.0f); - GPU_line_width(1.0f); + if (!draw_stretch) { + GPU_blend(true); - break; + UI_GetThemeColor4fv(TH_FACE, col1); + UI_GetThemeColor4fv(TH_FACE_SELECT, col2); + UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3); + col3[3] *= 0.2; /* Simulate dithering */ + GPU_batch_uniform_4fv(faces, "faceColor", col1); + GPU_batch_uniform_4fv(faces, "selectColor", col2); + GPU_batch_uniform_4fv(faces, "activeColor", col3); } - case SI_UVDT_BLACK: /* black/white */ - case SI_UVDT_WHITE: - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (sima->dt_uv == SI_UVDT_WHITE) { - immUniformColor3f(1.0f, 1.0f, 1.0f); - } - else { - immUniformColor3f(0.0f, 0.0f, 0.0f); - } - GPU_line_width(1.0f); - - break; - case SI_UVDT_OUTLINE: - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - imm_cpack(0x0); - GPU_line_width(3.0f); - break; - } + GPU_batch_draw(faces); - /* For more efficiency first transfer the entire buffer to vram. */ - GPUBatch *loop_batch = immBeginBatchAtMost(GPU_PRIM_LINE_LOOP, bm->totloop); - GPUVertBuf *loop_vbo = loop_batch->verts[0]; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); + if (!draw_stretch) { + GPU_blend(false); } } - immEnd(); - - /* Then draw each face contour separately. */ - if (loop_vbo->vertex_len != 0) { - GPU_batch_program_use_begin(loop_batch); - unsigned int index = 0, loop_vbo_count; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - GPU_batch_draw_range_ex(loop_batch, index, efa->len, false); - index += efa->len; + if (edges) { + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(true); + GPU_blend(true); } - loop_vbo_count = index; - GPU_batch_program_use_end(loop_batch); - immUnbindProgram(); - - - if (sima->dt_uv == SI_UVDT_OUTLINE) { - GPU_line_width(1.0f); - UI_GetThemeColor4fv(TH_WIRE_EDIT, col2); - - if ((sima->flag & SI_NO_DRAWEDGES) == 0) { - int sel; - UI_GetThemeColor4fv(TH_EDGE_SELECT, col1); - - if (interpedges) { - /* Create a color buffer. */ - static GPUVertFormat format = { 0 }; - static uint shdr_col; - if (format.attr_len == 0) { - shdr_col = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - } - - GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo_col, loop_vbo_count); - - index = 0; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - GPU_vertbuf_attr_set(vbo_col, shdr_col, index++, sel ? col1 : col2); - } - } - /* Reuse the UV buffer and add the color buffer. */ - GPU_batch_vertbuf_add_ex(loop_batch, vbo_col, true); - - /* Now draw each face contour separately with another builtin program. */ - GPU_batch_program_set_builtin(loop_batch, GPU_SHADER_2D_SMOOTH_COLOR); - GPU_matrix_bind(loop_batch->interface); - - GPU_batch_program_use_begin(loop_batch); - index = 0; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - GPU_batch_draw_range_ex(loop_batch, index, efa->len, false); - index += efa->len; - } - GPU_batch_program_use_end(loop_batch); + switch (sima->dt_uv) { + case SI_UVDT_DASH: + { + float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}; + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + + GPU_line_width(1.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + GPU_batch_uniform_4fv_array(edges, "colors", 2, (float *)dash_colors); + GPU_batch_uniform_2f(edges, "viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + GPU_batch_uniform_1i(edges, "colors_len", 2); /* "advanced" mode */ + GPU_batch_uniform_1f(edges, "dash_width", 4.0f); + GPU_batch_draw(edges); + break; + } + case SI_UVDT_BLACK: + case SI_UVDT_WHITE: + { + GPU_line_width(1.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); + if (sima->dt_uv == SI_UVDT_WHITE) { + GPU_batch_uniform_4f(edges, "color", 1.0f, 1.0f, 1.0f, 1.0f); } else { - GPUVertFormat *format = immVertexFormat(); - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - - /* Use batch here to avoid problems with `IMM_BUFFER_SIZE`. */ - GPUBatch *flat_edges_batch = immBeginBatchAtMost(GPU_PRIM_LINES, loop_vbo_count * 2); - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); - immAttrib4fv(color, sel ? col1 : col2); - - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } - } - immEnd(); - - GPU_batch_draw(flat_edges_batch); - GPU_batch_discard(flat_edges_batch); - - immUnbindProgram(); - } - } - else { - GPU_batch_uniform_4fv(loop_batch, "color", col2); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* no nice edges */ - GPU_batch_program_use_begin(loop_batch); - index = 0; - BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - GPU_batch_draw_range_ex(loop_batch, index, efa->len, false); - index += efa->len; + GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); } - GPU_batch_program_use_end(loop_batch); - immUnbindProgram(); + GPU_batch_draw(edges); + break; } - } - } - else { - immUnbindProgram(); - } - - GPU_batch_discard(loop_batch); - - if (sima->flag & SI_SMOOTH_UV) { - GPU_line_smooth(false); - GPU_blend(false); - } - - /* 5. draw face centers */ - - if (drawfaces) { - float cent[2]; - bool col_set = false; - - GPUVertFormat *format = immVertexFormat(); - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - - pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); - GPU_point_size(pointsize); - - immBeginAtMost(GPU_PRIM_POINTS, bm->totface); - - /* unselected faces */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - /* Only set color for the first face */ - if (!col_set) { - UI_GetThemeColor3fv(TH_WIRE, col1); - immAttrib3fv(color, col1); - - col_set = true; + case SI_UVDT_OUTLINE: + { + GPU_line_width(3.0f); + GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UNIFORM_COLOR); + GPU_batch_uniform_4f(edges, "color", 0.0f, 0.0f, 0.0f, 1.0f); + GPU_batch_draw(edges); + + UI_GetThemeColor4fv(TH_WIRE_EDIT, col1); + UI_GetThemeColor4fv(TH_EDGE_SELECT, col2); + + /* We could modify the vbo's data filling instead of modifying the provoking vert. */ + glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); + + GPU_line_width(1.0f); + GPU_batch_program_set_builtin(edges, (interpedges) + ? GPU_SHADER_2D_UV_EDGES_SMOOTH + : GPU_SHADER_2D_UV_EDGES); + GPU_batch_uniform_4fv(edges, "edgeColor", col1); + GPU_batch_uniform_4fv(edges, "selectColor", do_selected_edges ? col2 : col1); + GPU_batch_draw(edges); + + if (do_elem_order_fix && do_selected_edges) { + /* We have problem in this mode when face order make some edges + * appear unselected because an adjacent face is not selected and + * render after the selected face. + * So, to avoid sorting edges by state we just render selected edges + * on top. A bit overkill but it's simple. */ + GPU_blend(true); + GPU_batch_uniform_4fv(edges, "edgeColor", transparent); + GPU_batch_uniform_4fv(edges, "selectColor", col2); + GPU_batch_draw(edges); + GPU_blend(false); } - - uv_poly_center(efa, cent, cd_loop_uv_offset); - immVertex2fv(pos, cent); + glProvokingVertex(GL_LAST_VERTEX_CONVENTION); + break; } } - - col_set = false; - - /* selected faces */ - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - /* Only set color for the first face */ - if (!col_set) { - UI_GetThemeColor3fv(TH_FACE_DOT, col1); - immAttrib3fv(color, col1); - - col_set = true; - } - - uv_poly_center(efa, cent, cd_loop_uv_offset); - immVertex2fv(pos, cent); - } + if (sima->flag & SI_SMOOTH_UV) { + GPU_line_smooth(false); + GPU_blend(false); } - - immEnd(); - - immUnbindProgram(); } - - /* 6. draw uv vertices */ - - if (drawfaces != 2) { /* 2 means Mesh Face Mode */ - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* unselected uvs */ - immUniformThemeColor(TH_VERTEX); - pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); - GPU_point_size(pointsize); - - immBeginAtMost(GPU_PRIM_POINTS, bm->totloop); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - immVertex2fv(pos, luv->uv); + if (verts || facedots) { + float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); + UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); + if (verts) { + float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ + UI_GetThemeColor4fv(TH_VERTEX, col1); + GPU_blend(true); + GPU_enable_program_point_size(); + + GPU_batch_program_set_builtin(verts, GPU_SHADER_2D_UV_VERTS); + GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f); + GPU_batch_uniform_4fv(verts, "selectColor", (do_elem_order_fix) ? transparent : col2); + GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); + GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); + GPU_batch_draw(verts); + + if (do_elem_order_fix) { + /* We have problem in this mode when face order make some verts + * appear unselected because an adjacent face is not selected and + * render after the selected face. + * So, to avoid sorting verts by state we just render selected verts + * on top. A bit overkill but it's simple. */ + GPU_batch_uniform_4fv(verts, "vertColor", transparent); + GPU_batch_uniform_4fv(verts, "selectColor", col2); + GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); + GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); + GPU_batch_draw(verts); } - } - - immEnd(); - /* pinned uvs */ - /* give odd pointsizes odd pin pointsizes */ - GPU_point_size(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0)); - imm_cpack(0xFF); - - immBeginAtMost(GPU_PRIM_POINTS, bm->totloop); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_PINNED) - immVertex2fv(pos, luv->uv); - } + GPU_blend(false); + GPU_disable_program_point_size(); } - - immEnd(); - - /* selected uvs */ - immUniformThemeColor(TH_VERTEX_SELECT); - GPU_point_size(pointsize); - - immBeginAtMost(GPU_PRIM_POINTS, bm->totloop); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) - immVertex2fv(pos, luv->uv); - } + if (facedots) { + GPU_point_size(pointsize); + + UI_GetThemeColor4fv(TH_WIRE, col1); + GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS); + GPU_batch_uniform_4fv(facedots, "vertColor", col1); + GPU_batch_uniform_4fv(facedots, "selectColor", col2); + GPU_batch_draw(facedots); } - - immEnd(); - - immUnbindProgram(); } } - static void draw_uv_shadows_get( SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint) diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5c010a58137..e8ed5de82cb 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -205,6 +205,7 @@ data_to_c_simple(shaders/gpu_shader_point_uniform_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_aa_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_uniform_color_outline_aa_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_varying_color_outline_aa_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_point_varying_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_point_fixed_size_varying_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_3D_point_varying_size_vert.glsl SRC) @@ -216,6 +217,12 @@ data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_aa_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_aa_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_points_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_facedots_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_edges_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_faces_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_edituvs_stretch_vert.glsl SRC) + data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 1a1d40b32c2..86d68ebfc58 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -352,6 +352,13 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_WIDGET_SHADOW, GPU_SHADER_2D_NODELINK, GPU_SHADER_2D_NODELINK_INST, + /* specialized for edituv drawing */ + GPU_SHADER_2D_UV_VERTS, + GPU_SHADER_2D_UV_FACEDOTS, + GPU_SHADER_2D_UV_EDGES, + GPU_SHADER_2D_UV_EDGES_SMOOTH, + GPU_SHADER_2D_UV_FACES, + GPU_SHADER_2D_UV_FACES_STRETCH, GPU_NUM_BUILTIN_SHADERS /* (not an actual shader) */ } GPUBuiltinShader; diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index e0172579b3c..4fa0fae4c87 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -128,6 +128,7 @@ extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_uniform_color_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_outline_aa_frag_glsl[]; +extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_point_fixed_size_varying_color_vert_glsl[]; extern char datatoc_gpu_shader_3D_point_varying_size_vert_glsl[]; @@ -139,6 +140,12 @@ extern char datatoc_gpu_shader_2D_point_uniform_size_aa_vert_glsl[]; extern char datatoc_gpu_shader_2D_point_uniform_size_outline_aa_vert_glsl[]; extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_aa_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_points_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_edges_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_faces_vert_glsl[]; +extern char datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl[]; + extern char datatoc_gpu_shader_2D_line_dashed_uniform_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_frag_glsl[]; extern char datatoc_gpu_shader_2D_line_dashed_geom_glsl[]; @@ -928,6 +935,25 @@ static const GPUShaderStages builtin_shader_stages[GPU_NUM_BUILTIN_SHADERS] = { { datatoc_gpu_shader_2D_nodelink_vert_glsl, datatoc_gpu_shader_2D_nodelink_frag_glsl }, + [GPU_SHADER_2D_UV_VERTS] = + { datatoc_gpu_shader_2D_edituvs_points_vert_glsl, + datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl }, + [GPU_SHADER_2D_UV_FACEDOTS] = + { datatoc_gpu_shader_2D_edituvs_facedots_vert_glsl, + datatoc_gpu_shader_point_varying_color_frag_glsl }, + [GPU_SHADER_2D_UV_EDGES] = + { datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_UV_EDGES_SMOOTH] = + { datatoc_gpu_shader_2D_edituvs_edges_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_2D_UV_FACES] = + { datatoc_gpu_shader_2D_edituvs_faces_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl }, + [GPU_SHADER_2D_UV_FACES_STRETCH] = + { datatoc_gpu_shader_2D_edituvs_stretch_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_GPENCIL_STROKE] = { datatoc_gpu_shader_gpencil_stroke_vert_glsl, datatoc_gpu_shader_gpencil_stroke_frag_glsl, @@ -995,6 +1021,9 @@ static const char *gpu_shader_get_builtin_shader_defines( case GPU_SHADER_SIMPLE_LIGHTING_FLAT_COLOR: return "#define USE_FLAT_NORMAL\n"; + case GPU_SHADER_2D_UV_EDGES_SMOOTH: + return "#define SMOOTH_COLOR\n"; + default: return NULL; } diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl new file mode 100644 index 00000000000..76e9c066103 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_edges_vert.glsl @@ -0,0 +1,29 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec4 edgeColor; +uniform vec4 selectColor; + +in vec2 pos; +in int flag; + +#ifdef SMOOTH_COLOR +noperspective out vec4 finalColor; +#else +flat out vec4 finalColor; +#endif + +#define VERTEX_SELECT (1 << 0) +#define EDGE_SELECT (1 << 4) + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + +#ifdef SMOOTH_COLOR + bool is_select = (flag & VERTEX_SELECT) != 0; +#else + bool is_select = (flag & EDGE_SELECT) != 0; +#endif + + finalColor = (is_select) ? selectColor : edgeColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl new file mode 100644 index 00000000000..4f3f8917286 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_facedots_vert.glsl @@ -0,0 +1,17 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec4 vertColor; +uniform vec4 selectColor; + +in vec2 pos; +in int flag; + +out vec4 finalColor; + +#define FACE_SELECT (1 << 2) + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = ((flag & FACE_SELECT) != 0) ? selectColor : vertColor; +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl new file mode 100644 index 00000000000..82c8d3f0c4a --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_faces_vert.glsl @@ -0,0 +1,24 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec4 faceColor; +uniform vec4 selectColor; +uniform vec4 activeColor; + +in vec2 pos; +in int flag; + +flat out vec4 finalColor; + +#define FACE_SELECT (1 << 2) +#define FACE_ACTIVE (1 << 3) + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + + bool is_selected = (flag & FACE_SELECT) != 0; + bool is_active = (flag & FACE_ACTIVE) != 0; + + finalColor = (is_selected) ? selectColor : faceColor; + finalColor = (is_active) ? activeColor : finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl new file mode 100644 index 00000000000..d59e15a8f63 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_points_vert.glsl @@ -0,0 +1,42 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform vec4 vertColor; +uniform vec4 selectColor; +uniform vec4 pinnedColor; +uniform float pointSize; +uniform float outlineWidth; + +in vec2 pos; +in int flag; + +out vec4 fillColor; +out vec4 outlineColor; +out vec4 radii; + +#define VERTEX_SELECT (1 << 0) +#define VERTEX_PINNED (1 << 1) + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + gl_PointSize = pointSize; + + bool is_selected = (flag & VERTEX_SELECT) != 0; + bool is_pinned = (flag & VERTEX_PINNED) != 0; + + vec4 deselect_col = (is_pinned) ? pinnedColor : vertColor; + fillColor = (is_selected) ? selectColor : deselect_col; + outlineColor = (is_pinned) ? pinnedColor : vec4(fillColor.rgb, 0.0); + + // calculate concentric radii in pixels + float radius = 0.5 * pointSize; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= pointSize; +}
\ No newline at end of file diff --git a/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl new file mode 100644 index 00000000000..4588e41573b --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_edituvs_stretch_vert.glsl @@ -0,0 +1,49 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 pos; +in float stretch; + +noperspective out vec4 finalColor; + +vec3 weight_to_rgb(float weight) +{ + vec3 r_rgb; + float blend = ((weight / 2.0) + 0.5); + + if (weight <= 0.25) { /* blue->cyan */ + r_rgb[0] = 0.0; + r_rgb[1] = blend * weight * 4.0; + r_rgb[2] = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb[0] = 0.0; + r_rgb[1] = blend; + r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb[0] = blend * ((weight - 0.50) * 4.0); + r_rgb[1] = blend; + r_rgb[2] = 0.0; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb[0] = blend; + r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0)); + r_rgb[2] = 0.0; + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb[0] = 1.0; + r_rgb[1] = 0.0; + r_rgb[2] = 1.0; + } + + return r_rgb; +} + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = vec4(weight_to_rgb(stretch), 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl new file mode 100644 index 00000000000..e1f8203cb26 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_point_varying_color_varying_outline_aa_frag.glsl @@ -0,0 +1,30 @@ + +in vec4 radii; +in vec4 fillColor; +in vec4 outlineColor; +out vec4 fragColor; + +void main() { + float dist = length(gl_PointCoord - vec2(0.5)); + +// transparent outside of point +// --- 0 --- +// smooth transition +// --- 1 --- +// pure outline color +// --- 2 --- +// smooth transition +// --- 3 --- +// pure fill color +// ... +// dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); +} |