summaryrefslogtreecommitdiff
path: root/src/graphics/command.rs
diff options
context:
space:
mode:
authorTengu712 <genreihoutengu@gmail.com>2026-10-01 01:53:23 +0900
committerTengu712 <genreihoutengu@gmail.com>2026-10-01 01:53:23 +0900
commit2c104d7936193bb19eb52b3e4d47657ffb18a9d7 (patch)
tree6f90ea406a1506bbb37ee3aea52a29278524074a /src/graphics/command.rs
parente3835c956011c217e498b272490005dca457d402 (diff)
render text
Diffstat (limited to 'src/graphics/command.rs')
-rw-r--r--src/graphics/command.rs115
1 files changed, 115 insertions, 0 deletions
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<InstanceData>,
+ ) {
+ 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<InstanceData>,
+) {
+ 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;
+ }
+}