diff options
| author | LLLL Colonq <llll@colonq> | 2025-01-18 20:46:08 -0500 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2025-01-18 20:46:08 -0500 |
| commit | 6c00c069ccf08ef5e577c16acc78a5b1f53a0f8f (patch) | |
| tree | ca0cf7a5e042883cfa7fe95725d8eda35860d56e /src/font.rs | |
| parent | 82d1c94d999654bda5d40108393eade80b77342c (diff) | |
Rework font rendering, configurable resolution
Diffstat (limited to 'src/font.rs')
| -rw-r--r-- | src/font.rs | 149 |
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, ), ) |
