Curve Edit: Cleanup/Improve/Fix handles drawing

Now handles are drawn using index buffer instead of duplicating memory
requirement.

Also make use of shader tricks to draw handles antialiased, and respond to
UI scalling.

Make vertex point match edit mesh vertex size.
This commit is contained in:
Clément Foucault 2018-09-26 00:48:55 +02:00
parent c9d0873e90
commit 5158da9e37
7 changed files with 121 additions and 168 deletions

View File

@ -276,7 +276,7 @@ data_to_c_simple(modes/shaders/edit_mesh_overlay_ghost_clear_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_mix_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_mesh_overlay_facefill_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_frag.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_handle_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_handle_geom.glsl SRC)
data_to_c_simple(modes/shaders/edit_curve_overlay_loosevert_vert.glsl SRC)
data_to_c_simple(modes/shaders/edit_lattice_overlay_frag.glsl SRC)

View File

@ -45,14 +45,11 @@
#include "draw_cache_impl.h" /* own include */
#define SELECT 1
#define ACTIVE_NURB 1 << 7 /* last char bite */
#define HANDLE_SEL_OFFSET (TH_HANDLE_SEL_FREE - TH_HANDLE_FREE)
#define ACTIVE_NURB 1 << 2
/* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
enum {
COLOR_NURB_ULINE_ID = TH_HANDLE_SEL_AUTOCLAMP - TH_HANDLE_FREE + 1,
COLOR_NURB_SEL_ULINE_ID,
COLOR_ACTIVE_SPLINE,
COLOR_NURB_ULINE_ID = TH_HANDLE_AUTOCLAMP - TH_HANDLE_FREE + 2,
TOT_HANDLE_COL,
};
@ -678,10 +675,12 @@ static void curve_batch_cache_create_overlay_batches(Curve *cu)
const bool is_active = (i == rdata->actvert);
GPU_indexbuf_add_point_vert(&elb, vbo_len_used + 1);
for (int j = 0; j < 3; j++) {
char vflag = ((&bezt->f1)[j] & SELECT)
? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED)
: 0;
char vflag = ((&bezt->f1)[j] & SELECT) ? VFLAG_VERTEX_SELECTED : 0;
vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0;
vflag |= (is_active_nurb) ? ACTIVE_NURB : 0;
/* handle color id */
char col_id = (&bezt->h1)[j / 2];
vflag |= col_id << 3; /* << 3 because of ACTIVE_NURB */
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]);
GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
vbo_len_used += 1;
@ -695,10 +694,10 @@ static void curve_batch_cache_create_overlay_batches(Curve *cu)
for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) {
if (bp->hide == false) {
const bool is_active = (i == rdata->actvert);
char vflag = (bp->f1 & SELECT)
? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED)
: 0;
char vflag = (bp->f1 & SELECT) ? VFLAG_VERTEX_SELECTED : 0;
vflag |= (is_active) ? VFLAG_VERTEX_ACTIVE : 0;
vflag |= (is_active_nurb) ? ACTIVE_NURB : 0;
vflag |= COLOR_NURB_ULINE_ID << 3; /* << 3 because of ACTIVE_NURB */
GPU_indexbuf_add_point_vert(&elb, vbo_len_used);
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec);
GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
@ -720,78 +719,44 @@ static void curve_batch_cache_create_overlay_batches(Curve *cu)
}
if ((cache->overlay.edges == NULL) && (rdata->hide_handles == false)) {
/* Note: we could reference indices to vertices (above) */
if (cache->overlay.edges == NULL) {
GPUVertBuf *vbo = cache->overlay.verts->verts[0];
static GPUVertFormat format = { 0 };
static struct { uint pos, data; } attr_id;
if (format.attr_len == 0) {
/* initialize vertex format */
attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
const int edge_len = curve_render_data_overlay_edges_len_get(rdata);
const int vbo_len_capacity = edge_len * 2;
int vbo_len_used = 0;
GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
GPUIndexBufBuilder elb;
GPU_indexbuf_init(&elb, GPU_PRIM_LINES, vbo_len_capacity, vbo->vertex_len);
int curr_index = 0;
int i = 0;
for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) {
const bool is_active_nurb = (i == cu->actnu);
if (nu->bezt) {
int a = 0;
for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == false) {
char col_id;
for (int j = 0; j < 2; j += 1) {
/* same vertex twice, only check different selection */
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
vbo_len_used += 1;
col_id = (&bezt->h1)[j];
if ((&bezt->f1)[j * 2] & SELECT) {
col_id += HANDLE_SEL_OFFSET;
}
if (is_active_nurb) {
col_id |= ACTIVE_NURB;
}
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j * 2]);
GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
vbo_len_used += 1;
}
GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 0);
GPU_indexbuf_add_line_verts(&elb, curr_index + 1, curr_index + 2);
curr_index += 3;
}
}
}
else if (nu->bp) {
curr_index += 1;
int a = 1;
for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) {
if ((bp_prev->hide == false) && (bp_curr->hide == false)) {
char col_id = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? COLOR_NURB_SEL_ULINE_ID : COLOR_NURB_ULINE_ID;
if (is_active_nurb) {
col_id |= ACTIVE_NURB;
if (bp_prev->hide == false) {
if (bp_curr->hide == false) {
GPU_indexbuf_add_line_verts(&elb, curr_index - 1, curr_index + 0);
}
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec);
vbo_len_used += 1;
GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec);
GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
vbo_len_used += 1;
curr_index += 1;
}
}
}
}
if (vbo_len_capacity != vbo_len_used) {
GPU_vertbuf_data_resize(vbo, vbo_len_used);
}
cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
GPUIndexBuf *ibo = GPU_indexbuf_build(&elb);
cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, ibo, GPU_BATCH_OWNS_INDEX);
}
curve_render_data_free(rdata);

View File

@ -47,13 +47,12 @@ extern struct GlobalsUboStorage ts; /* draw_common.c */
extern char datatoc_common_globals_lib_glsl[];
extern char datatoc_edit_curve_overlay_loosevert_vert_glsl[];
extern char datatoc_edit_curve_overlay_frag_glsl[];
extern char datatoc_edit_curve_overlay_handle_vert_glsl[];
extern char datatoc_edit_curve_overlay_handle_geom_glsl[];
extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_point_uniform_color_frag_glsl[];
extern char datatoc_gpu_shader_flat_color_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_frag_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
/* *********** LISTS *********** */
/* All lists are per viewport specific datas.
@ -164,16 +163,16 @@ static void EDIT_CURVE_engine_init(void *vedata)
if (!e_data.overlay_edge_sh) {
e_data.overlay_edge_sh = DRW_shader_create_with_lib(
datatoc_edit_curve_overlay_loosevert_vert_glsl,
datatoc_edit_curve_overlay_handle_vert_glsl,
datatoc_edit_curve_overlay_handle_geom_glsl,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_gpu_shader_3D_smooth_color_frag_glsl,
datatoc_common_globals_lib_glsl, NULL);
}
if (!e_data.overlay_vert_sh) {
e_data.overlay_vert_sh = DRW_shader_create_with_lib(
datatoc_edit_curve_overlay_loosevert_vert_glsl, NULL,
datatoc_edit_curve_overlay_frag_glsl,
datatoc_gpu_shader_point_varying_color_frag_glsl,
datatoc_common_globals_lib_glsl, NULL);
}
}
@ -205,7 +204,7 @@ static void EDIT_CURVE_cache_init(void *vedata)
psl->overlay_edge_pass = DRW_pass_create(
"Curve Handle Overlay",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_WIRE);
DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND);
grp = DRW_shgroup_create(e_data.overlay_edge_sh, psl->overlay_edge_pass);
DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
@ -215,7 +214,7 @@ static void EDIT_CURVE_cache_init(void *vedata)
psl->overlay_vert_pass = DRW_pass_create(
"Curve Vert Overlay",
DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_POINT);
DRW_STATE_WRITE_COLOR | DRW_STATE_POINT);
grp = DRW_shgroup_create(e_data.overlay_vert_sh, psl->overlay_vert_pass);
DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);

View File

@ -1,22 +0,0 @@
flat in int vertFlag;
#define VERTEX_SELECTED (1 << 0)
#define VERTEX_ACTIVE (1 << 1)
out vec4 FragColor;
void main()
{
/* TODO: vertex size */
if ((vertFlag & VERTEX_SELECTED) != 0) {
FragColor = colorVertexSelect;
}
else if ((vertFlag & VERTEX_ACTIVE) != 0) {
FragColor = colorEditMeshActive;
}
else {
FragColor = colorVertex;
}
}

View File

@ -1,14 +1,30 @@
#define ACTIVE_NURB 1 << 7 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
#define VERTEX_ACTIVE 1 << 0
#define VERTEX_SELECTED 1 << 1
#define ACTIVE_NURB 1 << 2 /* Keep the same value of `ACTIVE_NURB` in `draw_cache_imp_curve.c` */
#define NURBS_EDGE_SELECTED (((vertFlag[1] & vertFlag[0]) & VERTEX_SELECTED) != 0)
layout(lines) in;
layout(line_strip, max_vertices = 6) out;
layout(triangle_strip, max_vertices = 10) out;
uniform vec2 viewportSize;
flat in int vertFlag[];
flat out vec4 finalColor;
out vec4 finalColor;
void output_line(vec2 offset, vec4 color)
{
finalColor = color;
gl_Position = gl_in[0].gl_Position;
gl_Position.xy += offset * gl_in[0].gl_Position.w;
EmitVertex();
gl_Position = gl_in[1].gl_Position;
gl_Position.xy += offset * gl_in[1].gl_Position.w;
EmitVertex();
}
void main()
{
@ -17,63 +33,53 @@ void main()
vec4 v1 = gl_in[0].gl_Position;
vec4 v2 = gl_in[1].gl_Position;
int is_active_nurb = vertFlag[1] & ACTIVE_NURB;
int color_id = vertFlag[1] ^ is_active_nurb;
int is_active_nurb = (vertFlag[1] & ACTIVE_NURB);
int color_id = (vertFlag[1] >> 3);
if (is_active_nurb != 0) {
/* draw the outline. */
vec2 v1_2 = (v2.xy/v2.w - v1.xy/v1.w);
vec2 offset;
if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
offset = vec2(2.0 / viewportSize.x, 0.0);
}
else {
offset = vec2(0.0, 2.0 / viewportSize.y);
}
bool edge_selected = (((vertFlag[1] | vertFlag[0]) & VERTEX_SELECTED) != 0);
finalColor = colorActiveSpline;
vec4 inner_color;
if (color_id == 0) inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree;
else if (color_id == 1) inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto;
else if (color_id == 2) inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect;
else if (color_id == 3) inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign;
else if (color_id == 4) inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp;
else inner_color = (NURBS_EDGE_SELECTED) ? colorNurbSelUline : colorNurbUline;
gl_Position = v1;
gl_Position.xy += offset * v1.w;
EmitVertex();
vec4 outer_color = (is_active_nurb != 0)
? mix(colorActiveSpline, inner_color, 0.25) /* Minimize active color bleeding on inner_color. */
: vec4(inner_color.rgb, 0.0);
gl_Position = v2;
gl_Position.xy += offset * v2.w;
EmitVertex();
vec2 v1_2 = (v2.xy/v2.w - v1.xy/v1.w);
vec2 offset = sizeEdge * 4.0 / viewportSize; /* 4.0 is eyeballed */
EndPrimitive();
gl_Position = v1;
gl_Position.xy -= offset * v1.w;
EmitVertex();
gl_Position = v2;
gl_Position.xy -= offset * v2.w;
EmitVertex();
EndPrimitive();
if (abs(v1_2.x * viewportSize.x) < abs(v1_2.y * viewportSize.y)) {
offset.y = 0.0;
}
else {
offset.x = 0.0;
}
if (color_id == 0) finalColor = colorHandleFree;
else if (color_id == 1) finalColor = colorHandleAuto;
else if (color_id == 2) finalColor = colorHandleVect;
else if (color_id == 3) finalColor = colorHandleAlign;
else if (color_id == 4) finalColor = colorHandleAutoclamp;
else if (color_id == 5) finalColor = colorHandleSelFree;
else if (color_id == 6) finalColor = colorHandleSelAuto;
else if (color_id == 7) finalColor = colorHandleSelVect;
else if (color_id == 8) finalColor = colorHandleSelAlign;
else if (color_id == 9) finalColor = colorHandleSelAutoclamp;
else if (color_id == 10) finalColor = colorNurbUline;
else if (color_id == 11) finalColor = colorNurbSelUline;
else finalColor = colorVertexSelect;
/* draw the transparent border (AA). */
if (is_active_nurb != 0) {
offset *= 0.75; /* Don't make the active "halo" appear very thick. */
output_line(offset * 2.0, vec4(colorActiveSpline.rgb, 0.0));
}
gl_Position = v1;
EmitVertex();
/* draw the outline. */
output_line(offset, outer_color);
gl_Position = v2;
EmitVertex();
/* draw the core of the line. */
output_line(vec2(0.0), inner_color);
/* draw the outline. */
output_line(-offset, outer_color);
/* draw the transparent border (AA). */
if (is_active_nurb != 0) {
output_line(offset * -2.0, vec4(colorActiveSpline.rgb, 0.0));
}
EndPrimitive();
}

View File

@ -0,0 +1,15 @@
/* Draw Curve Handles */
uniform mat4 ModelViewProjectionMatrix;
in vec3 pos;
in int data;
flat out int vertFlag;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
vertFlag = data;
}

View File

@ -7,33 +7,23 @@ uniform vec2 viewportSize;
in vec3 pos;
in int data;
/* these are the same for all vertices
* and does not need interpolation */
flat out int vertFlag;
flat out int clipCase;
out vec4 finalColor;
/* See fragment shader */
noperspective out vec4 eData1;
flat out vec4 eData2;
/* project to screen space */
vec2 proj(vec4 pos)
{
return (0.5 * (pos.xy / pos.w) + 0.5) * viewportSize;
}
#define VERTEX_ACTIVE (1 << 0)
#define VERTEX_SELECTED (1 << 1)
void main()
{
clipCase = 0;
if ((data & VERTEX_ACTIVE) != 0) {
finalColor = colorEditMeshActive;
}
if ((data & VERTEX_SELECTED) != 0) {
finalColor = colorVertexSelect;
}
else {
finalColor = colorVertex;
}
vec4 pPos = ModelViewProjectionMatrix * vec4(pos, 1.0);
/* only vertex position 0 is used */
eData1 = eData2 = vec4(1e10);
eData2.zw = proj(pPos);
vertFlag = data;
gl_Position = pPos;
gl_PointSize = sizeVertex;
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
gl_PointSize = sizeVertex * 2.0;
}