use geng::prelude::*;
const SHADER_SOURCE: &str = "
varying vec2 v_uv;
#ifdef VERTEX_SHADER
attribute vec2 a_pos;
uniform mat3 u_projection_matrix;
uniform mat3 u_view_matrix;
uniform mat3 u_model_matrix;
void main() {
v_uv = a_pos;
vec3 pos = u_projection_matrix * u_view_matrix * u_model_matrix * vec3(a_pos, 1.0);
gl_Position = vec4(pos.xy, 0.0, pos.z);
}
#endif
#ifdef FRAGMENT_SHADER
uniform sampler2D u_texture;
uniform vec4 u_color;
uniform vec4 u_border_color;
uniform float u_outline_distance;
float aa(float x) {
float w = length(vec2(dFdx(x), dFdy(x)));
return 1.0 - smoothstep(-w, w, x);
}
float read_sdf(sampler2D texture, vec2 uv) {
return 1.0 - 2.0 * texture2D(texture, uv).x;
}
void main() {
float dist = read_sdf(u_texture, v_uv);
float inside = aa(dist);
float inside_border = aa(dist - u_outline_distance);
vec4 outside_color = vec4(u_border_color.xyz, 0.0);
gl_FragColor = u_color * inside +
(1.0 - inside) * (
u_border_color * inside_border +
outside_color * (1.0 - inside_border)
);
}
#endif
";
struct State {
geng: Geng,
program: ugli::Program,
texture: ugli::Texture,
font: geng::Font,
}
impl State {
fn new(geng: &Geng) -> Self {
let font = geng::Font::new(
geng.ugli(),
include_bytes!("../crates/geng-font/src/default.ttf"),
&geng::font::Options {
pixel_size: 64.0,
max_distance: 0.25,
antialias: true,
..default()
},
)
.unwrap();
Self {
geng: geng.clone(),
program: geng.shader_lib().compile(SHADER_SOURCE).unwrap(),
texture: font
.create_text_sdf("Hello, Crabs", geng::TextAlign::CENTER, 64.0)
.unwrap(),
font,
}
}
}
impl geng::State for State {
fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
ugli::clear(framebuffer, Some(Rgba::BLACK), None, None);
let size = vec2(self.texture.size().map(|x| x as f32).aspect(), 1.0);
ugli::draw(
framebuffer,
&self.program,
ugli::DrawMode::TriangleFan,
&ugli::VertexBuffer::new_dynamic(
self.geng.ugli(),
vec![
draw2d::Vertex {
a_pos: vec2(0.0, 0.0),
},
draw2d::Vertex {
a_pos: vec2(1.0, 0.0),
},
draw2d::Vertex {
a_pos: vec2(1.0, 1.0),
},
draw2d::Vertex {
a_pos: vec2(0.0, 1.0),
},
],
),
(
ugli::uniforms! {
u_model_matrix: mat3::scale(size),
u_texture: &self.texture,
u_color: Rgba::WHITE,
u_border_color: Rgba::GRAY,
u_outline_distance: self.font.max_distance() / 2.0,
},
geng::Camera2d {
center: size / 2.0,
rotation: Angle::ZERO,
fov: 3.0,
}
.uniforms(framebuffer.size().map(|x| x as f32)),
),
ugli::DrawParameters {
blend_mode: Some(ugli::BlendMode::straight_alpha()),
..default()
},
);
}
}
fn main() {
logger::init();
geng::setup_panic_handler();
Geng::run("Font", |geng| async move {
geng.run_state(State::new(&geng)).await;
});
}