1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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;
}
}
|