From 2c104d7936193bb19eb52b3e4d47657ffb18a9d7 Mon Sep 17 00:00:00 2001 From: Tengu712 Date: Thu, 1 Oct 2026 01:53:23 +0900 Subject: render text --- src/graphics/command.rs | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/graphics/command.rs (limited to 'src/graphics/command.rs') diff --git a/src/graphics/command.rs b/src/graphics/command.rs new file mode 100644 index 0000000..54b6744 --- /dev/null +++ b/src/graphics/command.rs @@ -0,0 +1,115 @@ +use super::{ + InstanceData, + font::{self, CharAtlas}, +}; +use glam::Vec2; +use wgpu::Queue; + +pub enum HorizontalAlign { + Left, + Center, + Right, +} + +pub enum VerticalAlign { + Top, + Center, + Bottom, +} + +pub struct Text { + pub text: String, + pub origin: Vec2, + pub scale: u32, + pub h_align: HorizontalAlign, + pub v_align: VerticalAlign, +} + +pub enum RenderCommand { + Text(Text), +} + +impl RenderCommand { + /// 描画コマンドからインスタンス情報に変換するメソッド + /// + /// * screen_width - 画面幅 + /// * screen_height - 画面高 + /// * scale_factor - 画面拡大率 + /// * queue - queue + /// * char_atlas - 文字テクスチャアトラス + /// * buf - インスタンスバッファ + pub fn build( + &self, + screen_width: f32, + screen_height: f32, + scale_factor: f32, + queue: &Queue, + char_atlas: &mut CharAtlas, + buf: &mut Vec, + ) { + match self { + RenderCommand::Text(text) => build_text( + text, + screen_width, + screen_height, + scale_factor, + queue, + char_atlas, + buf, + ), + } + } +} + +fn build_text( + text: &Text, + screen_width: f32, + screen_height: f32, + scale_factor: f32, + queue: &Queue, + char_atlas: &mut CharAtlas, + buf: &mut Vec, +) { + let scale = text.scale as f32; + let line_height = font::line_height(scale); + let mut baseline = text.origin.y + font::ascent(scale); + + for line in text.text.split('\n') { + // NOTE: ピクセル境界に合わせるため、整数にする。 + // 最終的にRust側でNDCに変換するが、fragmentation時に整数に直る。 + let y = (baseline * scale_factor).round() / scale_factor; + let mut ox = text.origin.x; + let mut prev = None; + + for c in line.chars() { + let ci = char_atlas.acquire(queue, c, scale); + + if let Some(prev) = prev { + ox += font::kern(scale, prev, ci.glyph_id); + } + prev = Some(ci.glyph_id); + + if ci.alloc_id.is_none() { + ox += font::h_advance(scale, ci.glyph_id); + continue; + } + + // NOTE: ピクセル境界に合わせるため、整数にする。 + // 最終的にRust側でNDCに変換するが、fragmentation時に整数に直る。 + let x = (ox * scale_factor).round() / scale_factor; + let center_x = x + ci.x_offset + ci.width / 2.0; + let center_y = y + ci.y_offset + ci.height / 2.0; + buf.push(InstanceData { + position: Vec2::new( + center_x / screen_width * 2.0 - 1.0, + 1.0 - center_y / screen_height * 2.0, + ), + scale: Vec2::new(ci.width / screen_width, ci.height / screen_height), + uv: ci.uv, + }); + ox += font::h_advance(scale, ci.glyph_id); + } + + baseline += line_height; + } +} -- cgit v1.3.1