Good rounded rectangles finished
This commit is contained in:
parent
dba56df420
commit
de6429a2a1
|
@ -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));
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue