summaryrefslogtreecommitdiff
path: root/src/font.rs
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-01-18 20:46:08 -0500
committerLLLL Colonq <llll@colonq>2025-01-18 20:46:08 -0500
commit6c00c069ccf08ef5e577c16acc78a5b1f53a0f8f (patch)
treeca0cf7a5e042883cfa7fe95725d8eda35860d56e /src/font.rs
parent82d1c94d999654bda5d40108393eade80b77342c (diff)
Rework font rendering, configurable resolution
Diffstat (limited to 'src/font.rs')
-rw-r--r--src/font.rs149
1 files changed, 98 insertions, 51 deletions
diff --git a/src/font.rs b/src/font.rs
index fb8f133..047e1f7 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -1,6 +1,6 @@
use std::collections::HashMap;
-use crate::{context, texture, shader};
+use crate::{context, mesh, shader, texture};
use glow::HasContext;
pub const CHAR_WIDTH: i32 = 7;
@@ -11,6 +11,10 @@ pub const FONT_HEIGHT: i32 = 54;
pub struct Bitmap {
pub shader: shader::Shader,
pub font: texture::Texture,
+ pub vao: glow::VertexArray,
+ pub vertex_buf: glow::Buffer,
+ pub texcoords_buf: glow::Buffer,
+ pub index_buf: glow::Buffer,
}
impl Bitmap {
@@ -21,67 +25,110 @@ impl Bitmap {
include_str!("assets/shaders/bitmap/frag.glsl"),
);
let font = texture::Texture::new(ctx, include_bytes!("assets/fonts/simple.png"));
- Self {
- shader,
- font,
+ unsafe {
+ let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao");
+ ctx.gl.bind_vertex_array(Some(vao));
+
+ let vertex_buf = ctx.gl.create_buffer().expect("failed to create buffer object");
+ ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buf));
+ ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_VERTEX, 2, glow::FLOAT, false, 0, 0);
+ ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_VERTEX);
+
+ let texcoords_buf = ctx.gl.create_buffer().expect("failed to create buffer object");
+ ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_buf));
+ ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0);
+ ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_TEXCOORD);
+
+ let index_buf = ctx.gl.create_buffer().expect("failed to create buffer object");
+ ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buf));
+ Self {
+ shader,
+ font,
+ vao,
+ vertex_buf,
+ texcoords_buf,
+ index_buf,
+ }
}
}
pub fn render_text_helper(&self, ctx: &context::Context, pos: &glam::Vec2, text: &str, color: &glam::Vec3) {
- let mut width = 0;
- let mut linewidth = 0;
- let mut height = CHAR_HEIGHT;
+ let mut cur = glam::Vec2::new(0.0, 0.0);
+ let mut vertices = Vec::new();
+ let mut texcoords = Vec::new();
+ let mut indices = Vec::new();
+ let cwidth = CHAR_WIDTH as f32 / FONT_WIDTH as f32;
+ let cheight = CHAR_HEIGHT as f32 / FONT_HEIGHT as f32;
+ let row_len = FONT_WIDTH as u32 / CHAR_WIDTH as u32;
for c in text.chars() {
if c == '\n' {
- width = width.max(linewidth);
- linewidth = 0;
- height += CHAR_HEIGHT;
+ cur.x = 0.0;
+ cur.y += CHAR_HEIGHT as f32;
} else {
- linewidth += CHAR_WIDTH;
+ let idx = vertices.len() as u32;
+ vertices.push(cur);
+ vertices.push(cur + glam::Vec2::new(CHAR_WIDTH as f32, 0.0));
+ vertices.push(cur + glam::Vec2::new(CHAR_WIDTH as f32, CHAR_HEIGHT as f32));
+ vertices.push(cur + glam::Vec2::new(0.0, CHAR_HEIGHT as f32));
+ let cidx = c as u32 - ' ' as u32;
+ let col = cidx % row_len;
+ let row = cidx / row_len;
+ let tcbase = glam::Vec2::new(col as f32 * cwidth, row as f32 * cheight);
+ texcoords.push(tcbase + glam::Vec2::new(0.0, cheight));
+ texcoords.push(tcbase + glam::Vec2::new(cwidth, cheight));
+ texcoords.push(tcbase + glam::Vec2::new(cwidth, 0.0));
+ texcoords.push(tcbase);
+ indices.push(idx + 0); indices.push(idx + 1); indices.push(idx + 2);
+ indices.push(idx + 0); indices.push(idx + 3); indices.push(idx + 2);
+ cur.x += CHAR_WIDTH as f32;
}
}
- width = width.max(linewidth);
-
+ let index_bytes: Vec<u8> = indices.iter().flat_map(|x| x.to_ne_bytes()).collect();
self.shader.bind(ctx);
- let len = text.len().min(256);
- self.shader.set_i32(ctx, "text_length", len as _);
- let textvals: Vec<i32> = text.as_bytes().into_iter().take(len).map(|b| {
- *b as i32
- }).collect();
- self.shader.set_i32_array(ctx, "text[0]", &textvals);
- self.shader.set_i32(ctx, "char_width", CHAR_WIDTH as _);
- self.shader.set_i32(ctx, "char_height", CHAR_HEIGHT as _);
- self.shader.set_i32(ctx, "font_width", FONT_WIDTH as _);
- self.shader.set_i32(ctx, "font_height", FONT_HEIGHT as _);
- self.shader.set_i32(ctx, "text_width", width as _);
- self.shader.set_i32(ctx, "text_height", height as _);
- self.shader.set_vec3(ctx, "text_color", color as _);
- self.shader.set_mat4(
- ctx, "view",
- &glam::Mat4::from_scale(
- glam::Vec3::new(
- 2.0 / context::RENDER_WIDTH,
- 2.0 / context::RENDER_HEIGHT,
- 1.0,
- ),
- ),
+ self.font.bind(ctx);
+ let scale = glam::Vec2::new(2.0 / ctx.render_width, 2.0 / ctx.render_height);
+ let offset = glam::Vec2::new(
+ -ctx.render_width / 2.0,
+ ctx.render_height / 2.0 - CHAR_HEIGHT as f32,
);
- let halfwidth = width as f32 / 2.0;
- let halfheight = height as f32 / 2.0;
+ let npos = (glam::Vec2::new(pos.x, -pos.y) + offset) * scale;
+ self.shader.set_vec3(ctx, "text_color", color as _);
self.shader.set_mat4(
- ctx, "position",
+ ctx, "transform",
&glam::Mat4::from_scale_rotation_translation(
- glam::Vec3::new(halfwidth, halfheight, 1.0),
+ glam::Vec3::new(scale.x, scale.y, 1.0),
glam::Quat::IDENTITY,
- glam::Vec3::new(
- -context::RENDER_WIDTH / 2.0 + pos.x + halfwidth,
- context::RENDER_HEIGHT / 2.0 - pos.y - halfheight,
- 0.0,
- ),
- )
+ glam::Vec3::new(npos.x, npos.y, 0.0),
+ ),
);
- self.font.bind(ctx);
- ctx.render_no_geometry();
+ unsafe {
+ ctx.gl.bind_vertex_array(Some(self.vao));
+ ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buf));
+ ctx.gl.buffer_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ std::slice::from_raw_parts(
+ vertices.as_ptr() as _,
+ vertices.len() * std::mem::size_of::<f32>() * 2,
+ ),
+ glow::STATIC_DRAW,
+ );
+ ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.texcoords_buf));
+ ctx.gl.buffer_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ std::slice::from_raw_parts(
+ texcoords.as_ptr() as _,
+ texcoords.len() * std::mem::size_of::<f32>() * 2,
+ ),
+ glow::STATIC_DRAW,
+ );
+ ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buf));
+ ctx.gl.buffer_data_u8_slice(
+ glow::ELEMENT_ARRAY_BUFFER,
+ &index_bytes,
+ glow::STATIC_DRAW,
+ );
+ ctx.gl.draw_elements(glow::TRIANGLES, indices.len() as _, glow::UNSIGNED_INT, 0);
+ }
}
pub fn render_text(&self, ctx: &context::Context, pos: &glam::Vec2, text: &str) {
@@ -180,8 +227,8 @@ impl TrueType {
ctx, "view",
&glam::Mat4::from_scale(
glam::Vec3::new(
- 2.0 / context::RENDER_WIDTH,
- 2.0 / context::RENDER_HEIGHT,
+ 2.0 / ctx.render_width,
+ 2.0 / ctx.render_height,
1.0,
),
),
@@ -193,8 +240,8 @@ impl TrueType {
glam::Vec3::new(width as f32 / 2.0, self.cellheight as f32 / 2.0, 1.0),
glam::Quat::IDENTITY,
glam::Vec3::new(
- -context::RENDER_WIDTH / 2.0 + pos.x + width as f32 / 2.0,
- context::RENDER_HEIGHT / 2.0 - pos.y - self.cellheight as f32 / 2.0,
+ -ctx.render_width / 2.0 + pos.x + width as f32 / 2.0,
+ ctx.render_height / 2.0 - pos.y - self.cellheight as f32 / 2.0,
0.0,
),
)