Good rounded rectangles finished

This commit is contained in:
Allen Webster 2019-10-08 12:02:04 -07:00
parent dba56df420
commit de6429a2a1
6 changed files with 111 additions and 256 deletions

View File

@ -131,253 +131,34 @@ end_render_section(Render_Target *target){
////////////////////////////////
internal void
draw_rectangle_sharp(Render_Target *target, Rect_f32 rect, u32 color){
draw_rectangle_outline(Render_Target *target, Rect_f32 rect, f32 roundness, f32 thickness, u32 color){
if (roundness < epsilon_f32){
roundness = 0.f;
}
thickness = clamp_bot(1.f, thickness);
f32 half_thickness = thickness*0.5f;
Render_Vertex vertices[6] = {};
vertices[0].xy = V2(rect.x0, rect.y0);
vertices[1].xy = V2(rect.x1, rect.y0);
vertices[2].xy = V2(rect.x0, rect.y1);
vertices[3].xy = V2(rect.x1, rect.y0);
vertices[4].xy = V2(rect.x0, rect.y1);
vertices[5].xy = V2(rect.x1, rect.y1);
Vec4_f32 c = unpack_color4(color);
for (i32 i = 0; i < 6; i += 1){
vertices[i].color = c;
}
draw__write_vertices_in_current_group(target, vertices, 6);
}
global b32 filled_round_corner = false;
global_const i32 baked_tri_count = 12;
global Vec2_f32 baked_round_corner[baked_tri_count + 1] = {};
internal void
bake_round_corner(void){
if (!filled_round_corner){
filled_round_corner = true;
Range_f32 theta = If32(0.f, half_pi_f32);
for (i32 k = 0; k < baked_tri_count + 1; k += 1){
f32 t = ((f32)k)/((f32)baked_tri_count);
f32 theta1 = lerp(t, theta);
baked_round_corner[k] = V2f32(cos_f32(theta1), sin_f32(theta1));
}
}
}
internal void
draw_round_corners(Render_Target *target, Rect_f32 mid, f32 roundness, u32 color){
bake_round_corner();
for (i32 i = 0; i < 2; i += 1){
for (i32 j = 0; j < 2; j += 1){
Vec2_f32 d = {};
Vec2_f32 p = {};
if (i == 0){
if (j == 0){
p = V2f32(mid.x0, mid.y0);
d = V2f32(-1.f, -1.f);
}
else{
p = V2f32(mid.x1, mid.y0);
d = V2f32( 1.f, -1.f);
}
}
else{
if (j == 0){
p = V2f32(mid.x0, mid.y1);
d = V2f32(-1.f, 1.f);
}
else{
p = V2f32(mid.x1, mid.y1);
d = V2f32( 1.f, 1.f);
}
}
d *= roundness;
Render_Vertex vertices[baked_tri_count*3] = {};
i32 m = 0;
for (i32 k = 0; k < baked_tri_count; k += 1){
Vec2_f32 p0 = baked_round_corner[k + 0];
Vec2_f32 p1 = baked_round_corner[k + 1];
vertices[m].xy = p;
m += 1;
vertices[m].xy = p + hadamard(p0, d);
m += 1;
vertices[m].xy = p + hadamard(p1, d);
m += 1;
}
Vec4_f32 c = unpack_color4(color);
for (i32 k = 0; k < ArrayCount(vertices); k += 1){
vertices[k].color = c;
}
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
vertices[0].xy = V2f32(rect.x0, rect.y0);
vertices[1].xy = V2f32(rect.x1, rect.y0);
vertices[2].xy = V2f32(rect.x0, rect.y1);
vertices[3].xy = V2f32(rect.x1, rect.y0);
vertices[4].xy = V2f32(rect.x0, rect.y1);
vertices[5].xy = V2f32(rect.x1, rect.y1);
Vec2_f32 center = rect_center(rect);
for (i32 i = 0; i < ArrayCount(vertices); i += 1){
vertices[i].uvw = V3f32(center.x, center.y, roundness);
vertices[i].color = color;
vertices[i].half_thickness = half_thickness;
}
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
internal void
draw_rectangle(Render_Target *target, Rect_f32 rect, f32 roundness, u32 color){
if (roundness < epsilon_f32){
draw_rectangle_sharp(target, rect, color);
}
else{
Vec2_f32 dim = rect_dim(rect);
Vec2_f32 half_dim = dim*0.5f;
roundness = min(roundness, half_dim.x);
roundness = min(roundness, half_dim.y);
Rect_f32 mid = rect_inner(rect, roundness);
b32 has_x = (mid.x1 > mid.x0);
b32 has_y = (mid.y1 > mid.y0);
if (has_x && has_y){
draw_rectangle_sharp(target, mid, color);
}
if (has_x){
draw_rectangle_sharp(target,
Rf32(mid.x0, rect.y0, mid.x1, mid.y0),
color);
draw_rectangle_sharp(target,
Rf32(mid.x0, mid.y0, mid.x1, rect.y1),
color);
}
if (has_y){
draw_rectangle_sharp(target,
Rf32(rect.x0, mid.y0, mid.x0, mid.y1),
color);
draw_rectangle_sharp(target,
Rf32(mid.x1, mid.y0, rect.x1, mid.y1),
color);
}
draw_round_corners(target, mid, roundness, color);
}
}
internal void
draw_rectangle_outline(Render_Target *target, Rect_f32 rect, f32 roundness, f32 thickness, u32 color){
Vec2_f32 dim = rect_dim(rect);
Vec2_f32 half_dim = dim*0.5f;
f32 max_thickness = min(half_dim.x, half_dim.y);
thickness = clamp(1.f, thickness, max_thickness);
Rect_f32 inner = rect_inner(rect, thickness);
if (roundness < epsilon_f32){
Render_Vertex vertices[24] = {};
vertices[ 0].xy = V2(rect.x0, rect.y0);
vertices[ 1].xy = V2(inner.x0, inner.y0);
vertices[ 2].xy = V2(rect.x1, rect.y0);
vertices[ 3].xy = V2(inner.x0, inner.y0);
vertices[ 4].xy = V2(rect.x1, rect.y0);
vertices[ 5].xy = V2(inner.x1, inner.y0);
vertices[ 6].xy = V2(rect.x1, rect.y0);
vertices[ 7].xy = V2(inner.x1, inner.y0);
vertices[ 8].xy = V2(rect.x1, rect.y1);
vertices[ 9].xy = V2(inner.x1, inner.y0);
vertices[10].xy = V2(rect.x1, rect.y1);
vertices[11].xy = V2(inner.x1, inner.y1);
vertices[12].xy = V2(rect.x1, rect.y1);
vertices[13].xy = V2(inner.x1, inner.y1);
vertices[14].xy = V2(rect.x0, rect.y1);
vertices[15].xy = V2(inner.x1, inner.y1);
vertices[16].xy = V2(rect.x0, rect.y1);
vertices[17].xy = V2(inner.x0, inner.y1);
vertices[18].xy = V2(rect.x0, rect.y1);
vertices[19].xy = V2(inner.x0, inner.y1);
vertices[20].xy = V2(rect.x0, rect.y0);
vertices[21].xy = V2(inner.x0, inner.y1);
vertices[22].xy = V2(rect.x0, rect.y0);
vertices[23].xy = V2(inner.x0, inner.y0);
Vec4_f32 c = unpack_color4(color);
for (i32 i = 0; i < ArrayCount(vertices); i += 1){
vertices[i].color = c;
}
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
else{
roundness = min(roundness, half_dim.x);
roundness = min(roundness, half_dim.y);
Rect_f32 mid = rect_inner(rect, roundness);
b32 has_x = (mid.x1 > mid.x0);
b32 has_y = (mid.y1 > mid.y0);
if (has_x){
draw_rectangle_sharp(target,
Rf32(mid.x0, rect.y0, mid.x1, inner.y0),
color);
draw_rectangle_sharp(target,
Rf32(mid.x0, inner.y1, mid.x1, rect.y1),
color);
}
if (has_y){
draw_rectangle_sharp(target,
Rf32(rect.x0, mid.y0, inner.x0, mid.y1),
color);
draw_rectangle_sharp(target,
Rf32(inner.x1, mid.y0, rect.x1, mid.y1),
color);
}
if (roundness <= thickness){
draw_round_corners(target, mid, roundness, color);
}
else{
bake_round_corner();
for (i32 i = 0; i < 2; i += 1){
for (i32 j = 0; j < 2; j += 1){
Vec2_f32 d = {};
Vec2_f32 p = {};
if (i == 0){
if (j == 0){
p = V2f32(mid.x0, mid.y0);
d = V2f32(-1.f, -1.f);
}
else{
p = V2f32(mid.x1, mid.y0);
d = V2f32( 1.f, -1.f);
}
}
else{
if (j == 0){
p = V2f32(mid.x0, mid.y1);
d = V2f32(-1.f, 1.f);
}
else{
p = V2f32(mid.x1, mid.y1);
d = V2f32( 1.f, 1.f);
}
}
Vec2_f32 d1 = d*roundness;
Vec2_f32 d2 = d*(roundness - thickness);
Render_Vertex vertices[baked_tri_count*6] = {};
i32 m = 0;
for (i32 k = 0; k < baked_tri_count; k += 1){
Vec2_f32 p0 = baked_round_corner[k + 0];
Vec2_f32 p1 = baked_round_corner[k + 1];
vertices[m].xy = p + hadamard(p0, d1);
m += 1;
vertices[m].xy = p + hadamard(p0, d2);
m += 1;
vertices[m].xy = p + hadamard(p1, d1);
m += 1;
vertices[m].xy = p + hadamard(p0, d2);
m += 1;
vertices[m].xy = p + hadamard(p1, d1);
m += 1;
vertices[m].xy = p + hadamard(p1, d2);
m += 1;
}
Vec4_f32 c = unpack_color4(color);
for (i32 k = 0; k < ArrayCount(vertices); k += 1){
vertices[k].color = c;
}
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
}
}
}
draw_rectangle_outline(target, rect, roundness, max(dim.x, dim.y), color);
}
internal void
@ -416,12 +197,12 @@ draw_font_glyph(Render_Target *target, Face *face, u32 codepoint, f32 x, f32 y,
vertices[3] = vertices[1];
vertices[4] = vertices[2];
Vec4 c = unpack_color4(color);
for (i32 i = 0; i < 6; i += 1){
vertices[i].color = c;
for (i32 i = 0; i < ArrayCount(vertices); i += 1){
vertices[i].color = color;
vertices[i].half_thickness = 0.f;
}
draw__write_vertices_in_current_group(target, vertices, 6);
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
////////////////////////////////

View File

@ -18,9 +18,10 @@ struct Render_Free_Texture{
};
struct Render_Vertex{
Vec2 xy;
Vec3 uvw;
Vec4 color;
Vec2_f32 xy;
Vec3_f32 uvw;
u32 color;
f32 half_thickness;
};
struct Render_Vertex_Array_Node{

View File

@ -441,8 +441,8 @@ default_buffer_render_caller(Application_Links *app, Frame_Info frame_info, View
}
// NOTE(allen): Roundness
f32 cursor_roundness = 0.f;
f32 mark_thickness = 0.f;
f32 cursor_roundness = 4.f;
f32 mark_thickness = 2.f;
// NOTE(allen): Highlight range
b32 has_highlight_range = false;

View File

@ -2340,6 +2340,34 @@ draw_character_block(Application_Links *app, Text_Layout_ID layout, i64 pos, f32
internal void
draw_character_block(Application_Links *app, Text_Layout_ID layout, Range_i64 range, f32 roundness, int_color color){
if (range.first < range.one_past_last){
i64 i = range.first;
Rect_f32 first_rect = text_layout_character_on_screen(app, layout, i);
i += 1;
Range_f32 y = rect_range_y(first_rect);
Range_f32 x = rect_range_x(first_rect);
for (;i < range.one_past_last; i += 1){
Rect_f32 rect = text_layout_character_on_screen(app, layout, i);
if (rect.x0 < rect.x1 && rect.y0 < rect.y1){
Range_f32 new_y = rect_range_y(rect);
Range_f32 new_x = rect_range_x(rect);
b32 joinable = false;
if (new_y == y && (range_overlap(x, new_x) || x.max == new_x.min || new_x.max == x.min)){
joinable = true;
}
if (!joinable){
draw_rectangle(app, Rf32(x, y), roundness, color);
y = new_y;
x = new_x;
}
else{
x = range_union(x, new_x);
}
}
}
draw_rectangle(app, Rf32(x, y), roundness, color);
}
for (i64 i = range.first; i < range.one_past_last; i += 1){
draw_character_block(app, layout, i, roundness, color);
}

View File

@ -51,6 +51,7 @@ GL_FUNC(glDisableVertexAttribArray, void, (GLuint index))
GL_FUNC(glEnableVertexAttribArray, void, (GLuint index))
GL_FUNC(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer))
GL_FUNC(glVertexAttribIPointer, void, (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer))
GL_FUNC(glUniform1f, void, (GLint location, GLfloat v0))
GL_FUNC(glUniform2f, void, (GLint location, GLfloat v0, GLfloat v1))

View File

@ -68,32 +68,68 @@ uniform vec2 view_t;
uniform mat2x2 view_m;
in vec2 vertex_p;
in vec3 vertex_t;
in vec4 vertex_c;
in uint vertex_c;
in float vertex_ht;
smooth out vec4 fragment_color;
smooth out vec3 uvw;
smooth out vec2 xy;
smooth out vec2 adjusted_half_dim;
smooth out float half_thickness;
void main(void)
{
gl_Position = vec4(view_m*(vertex_p - view_t), 0.f, 1.f);
fragment_color = vertex_c;
gl_Position = vec4(view_m*(vertex_p - view_t), 0.0, 1.0);
fragment_color.b = ((vertex_c )&0xFF)/255.0;
fragment_color.g = ((vertex_c>> 8)&0xFF)/255.0;
fragment_color.r = ((vertex_c>>16)&0xFF)/255.0;
fragment_color.a = ((vertex_c>>24)&0xFF)/255.0;
uvw = vertex_t;
vec2 center = vertex_t.xy;
vec2 half_dim = abs(vertex_p - center);
adjusted_half_dim = half_dim - vertex_t.zz + vec2(0.5, 0.5);
half_thickness = vertex_ht;
xy = vertex_p;
}
)foo";
char *gl__fragment = R"foo(
smooth in vec4 fragment_color;
smooth in vec3 uvw;
smooth in vec2 xy;
smooth in vec2 adjusted_half_dim;
smooth in float half_thickness;
uniform sampler2DArray sampler;
out vec4 out_color;
float rectangle_sd(vec2 p, vec2 b){
vec2 d = abs(p) - b;
return(length(max(d, vec2(0.0, 0.0))) + min(max(d.x, d.y), 0.0));
}
void main(void)
{
out_color = vec4(fragment_color.xyz, fragment_color.a*texture(sampler, uvw).r);
float has_thickness = (step(0.49, half_thickness));
float does_not_have_thickness = 1.0 - has_thickness;
float sample_value = texture(sampler, uvw).r;
sample_value *= does_not_have_thickness;
vec2 center = uvw.xy;
float roundness = uvw.z;
float sd = rectangle_sd(xy - center, adjusted_half_dim);
sd = sd - roundness;
sd = abs(sd + half_thickness) - half_thickness;
float shape_value = 1.0 - smoothstep(-1.0, 0.0, sd);
shape_value *= has_thickness;
out_color = vec4(fragment_color.xyz, fragment_color.a*(sample_value + shape_value));
}
)foo";
#define AttributeList(X) \
X(vertex_p) \
X(vertex_t) \
X(vertex_c)
X(vertex_c) \
X(vertex_ht)
#define UniformList(X) \
X(view_t) \
@ -265,9 +301,16 @@ gl_render(Render_Target *t){
glEnableVertexAttribArray(gpu_program.vertex_p);
glEnableVertexAttribArray(gpu_program.vertex_t);
glEnableVertexAttribArray(gpu_program.vertex_c);
glVertexAttribPointer(gpu_program.vertex_p, 2, GL_FLOAT, true, sizeof(Render_Vertex), GLOffset(Render_Vertex, xy));
glVertexAttribPointer(gpu_program.vertex_t, 3, GL_FLOAT, true, sizeof(Render_Vertex), GLOffset(Render_Vertex, uvw));
glVertexAttribPointer(gpu_program.vertex_c, 4, GL_FLOAT, true, sizeof(Render_Vertex), GLOffset(Render_Vertex, color));
glEnableVertexAttribArray(gpu_program.vertex_ht);
glVertexAttribPointer(gpu_program.vertex_p, 2, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, xy));
glVertexAttribPointer(gpu_program.vertex_t, 3, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, uvw));
glVertexAttribIPointer(gpu_program.vertex_c, 1, GL_UNSIGNED_INT, sizeof(Render_Vertex),
GLOffset(Render_Vertex, color));
glVertexAttribPointer(gpu_program.vertex_ht, 1, GL_FLOAT, true, sizeof(Render_Vertex),
GLOffset(Render_Vertex, half_thickness));
glUniform2f(gpu_program.view_t, width/2.f, height/2.f);
f32 m[4] = {
@ -281,6 +324,7 @@ gl_render(Render_Target *t){
glDisableVertexAttribArray(gpu_program.vertex_p);
glDisableVertexAttribArray(gpu_program.vertex_t);
glDisableVertexAttribArray(gpu_program.vertex_c);
glDisableVertexAttribArray(gpu_program.vertex_ht);
}
}