diff --git a/headers/enduro2d/high/components/label.hpp b/headers/enduro2d/high/components/label.hpp index 47de759d..7ca7b027 100644 --- a/headers/enduro2d/high/components/label.hpp +++ b/headers/enduro2d/high/components/label.hpp @@ -54,6 +54,24 @@ namespace e2d label& filtering(bool value) noexcept; bool filtering() const noexcept; + + label& smoothing(f32 value) noexcept; + f32 smoothing() const noexcept; + + label& outline_distance(f32 value) noexcept; + f32 outline_distance() const noexcept; + + label& outline_color(const color32& value) noexcept; + color32 outline_color() const noexcept; + + label& shadow_smoothing(f32 value) noexcept; + f32 shadow_smoothing() const noexcept; + + label& shadow_offset(const v2f& value) noexcept; + v2f shadow_offset() const noexcept; + + label& shadow_color(const color32& value) noexcept; + color32 shadow_color() const noexcept; private: str32 text_; font_asset::ptr font_; @@ -62,6 +80,12 @@ namespace e2d haligns haligh_ = haligns::left; valigns valign_ = valigns::baseline; bool filtering_ = true; + f32 smoothing_ = 0.f; + f32 outline_distance_ = 0.f; + color32 outline_color_ = color32::white(); + f32 shadow_smoothing_ = 0.f; + v2f shadow_offset_; + color32 shadow_color_ = color32::white(); }; template <> @@ -160,4 +184,58 @@ namespace e2d inline bool label::filtering() const noexcept { return filtering_; } + + inline label& label::smoothing(f32 value) noexcept { + smoothing_ = value; + return *this; + } + + inline f32 label::smoothing() const noexcept { + return smoothing_; + } + + inline label& label::outline_distance(f32 value) noexcept { + outline_distance_ = value; + return *this; + } + + inline f32 label::outline_distance() const noexcept { + return outline_distance_; + } + + inline label& label::outline_color(const color32& value) noexcept { + outline_color_ = value; + return *this; + } + + inline color32 label::outline_color() const noexcept { + return outline_color_; + } + + inline label& label::shadow_smoothing(f32 value) noexcept { + shadow_smoothing_ = value; + return *this; + } + + inline f32 label::shadow_smoothing() const noexcept { + return shadow_smoothing_; + } + + inline label& label::shadow_offset(const v2f& value) noexcept { + shadow_offset_ = value; + return *this; + } + + inline v2f label::shadow_offset() const noexcept { + return shadow_offset_; + } + + inline label& label::shadow_color(const color32& value) noexcept { + shadow_color_ = value; + return *this; + } + + inline color32 label::shadow_color() const noexcept { + return shadow_color_; + } } diff --git a/samples/bin/library/sdf_shader.frag b/samples/bin/library/sdf_shader.frag index 052e5143..9175000e 100644 --- a/samples/bin/library/sdf_shader.frag +++ b/samples/bin/library/sdf_shader.frag @@ -1,14 +1,24 @@ uniform sampler2D u_texture; +uniform lowp float u_smoothing; +uniform lowp float u_outline_distance;// Between 0 and 0.5, 0 = thick outline, 0.5 = no outline +uniform lowp float u_shadow_smoothing;// Between 0 and 0.5 +uniform lowp vec2 u_shadow_offset; // Between 0 and spread / texture_size +uniform lowp vec4 u_shadow_color; +uniform lowp vec4 u_outline_color; varying vec2 v_st0; varying vec4 v_color; -const float smoothing = 1.0 / 16.0; - void main() { - vec2 st = vec2(v_st0.s, 1.0 - v_st0.t); - gl_FragColor = texture2D(u_texture, st) * v_color; - float distance = texture2D(u_texture, st).a; - float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance); - gl_FragColor = vec4(v_color.rgb, v_color.a * alpha); + lowp vec2 st = vec2(v_st0.s, 1.0 - v_st0.t); + lowp float distance = texture2D(u_texture, st).a; + lowp float outline_factor = smoothstep(0.5 - u_smoothing, 0.5 + u_smoothing, distance); + lowp vec4 color = mix(u_outline_color, v_color, outline_factor); + lowp float alpha = smoothstep(u_outline_distance - u_smoothing, u_outline_distance + u_smoothing, distance); + lowp vec4 text = vec4(color.rgb, color.a * alpha); + lowp float shadow_distance = texture2D(u_texture, st - u_shadow_offset).a; + lowp float shadow_alpha = smoothstep(0.5 - u_shadow_smoothing, 0.5 + u_shadow_smoothing, shadow_distance); + lowp vec4 shadow = vec4(u_shadow_color.rgb, u_shadow_color.a * shadow_alpha); + + gl_FragColor = mix(shadow, text, text.a); } diff --git a/sources/enduro2d/high/components/label.cpp b/sources/enduro2d/high/components/label.cpp index 6347e1bd..5be2edbe 100644 --- a/sources/enduro2d/high/components/label.cpp +++ b/sources/enduro2d/high/components/label.cpp @@ -43,7 +43,13 @@ namespace e2d "width" : { "type" : "number" }, "halign" : { "$ref": "#/definitions/haligns" }, "valign" : { "$ref": "#/definitions/valigns" }, - "filtering" : { "type" : "boolean" } + "filtering" : { "type" : "boolean" }, + "smoothing" : { "type" : "number" }, + "outline_distance" : { "type" : "number" }, + "outline_color" : { "$ref": "#/common_definitions/color" }, + "shadow_smoothing" : { "type" : "number" }, + "shadow_offset" : { "$ref": "#/common_definitions/v2" }, + "shadow_color" : { "$ref": "#/common_definitions/color" } }, "definitions" : { "haligns" : { @@ -138,6 +144,60 @@ namespace e2d component.filtering(filtering); } + if ( ctx.root.HasMember("smoothing") ) { + f32 smoothing = component.filtering(); + if ( !json_utils::try_parse_value(ctx.root["smoothing"], smoothing) ) { + the().error("LABEL: Incorrect formatting of 'smoothing' property"); + return false; + } + component.smoothing(smoothing); + } + + if ( ctx.root.HasMember("outline_distance") ) { + f32 outline_distance = component.outline_distance(); + if ( !json_utils::try_parse_value(ctx.root["outline_distance"], outline_distance) ) { + the().error("LABEL: Incorrect formatting of 'outline_distance' property"); + return false; + } + component.outline_distance(outline_distance); + } + + if ( ctx.root.HasMember("outline_color") ) { + color32 outline_color = component.outline_color(); + if ( !json_utils::try_parse_value(ctx.root["outline_color"], outline_color) ) { + the().error("LABEL: Incorrect formatting of 'outline_color' property"); + return false; + } + component.outline_color(outline_color); + } + + if ( ctx.root.HasMember("shadow_smoothing") ) { + f32 shadow_smoothing = component.shadow_smoothing(); + if ( !json_utils::try_parse_value(ctx.root["shadow_smoothing"], shadow_smoothing) ) { + the().error("LABEL: Incorrect formatting of 'shadow_smoothing' property"); + return false; + } + component.shadow_smoothing(shadow_smoothing); + } + + if ( ctx.root.HasMember("shadow_offset") ) { + v2f shadow_offset = component.shadow_offset(); + if ( !json_utils::try_parse_value(ctx.root["shadow_offset"], shadow_offset) ) { + the().error("LABEL: Incorrect formatting of 'shadow_offset' property"); + return false; + } + component.shadow_offset(shadow_offset); + } + + if ( ctx.root.HasMember("shadow_color") ) { + color32 shadow_color = component.shadow_color(); + if ( !json_utils::try_parse_value(ctx.root["shadow_color"], shadow_color) ) { + the().error("LABEL: Incorrect formatting of 'shadow_color' property"); + return false; + } + component.shadow_color(shadow_color); + } + return true; } diff --git a/sources/enduro2d/high/systems/label_system.cpp b/sources/enduro2d/high/systems/label_system.cpp index c37763b5..ec1f49df 100644 --- a/sources/enduro2d/high/systems/label_system.cpp +++ b/sources/enduro2d/high/systems/label_system.cpp @@ -284,11 +284,19 @@ namespace e2d ? render::sampler_mag_filter::linear : render::sampler_mag_filter::nearest; + color sc(l.shadow_color()); + color oc(l.outline_color()); r.properties(render::property_block() .sampler("u_texture", render::sampler_state() .texture(texture_p->content()) .min_filter(min_filter) - .mag_filter(mag_filter))); + .mag_filter(mag_filter)) + .property("u_smoothing", l.smoothing()) + .property("u_outline_distance", l.outline_distance()) + .property("u_shadow_smoothing", l.shadow_smoothing()) + .property("u_shadow_offset", l.shadow_offset()) + .property("u_shadow_color", make_vec4(sc.r, sc.g, sc.b, sc.a)) + .property("u_outline_color", make_vec4(oc.r, oc.g, oc.b, oc.a))); } });