1#[cfg(feature = "serde")]
4#[macro_use]
5extern crate serde;
6
7mod char;
8mod config_parse_error;
9mod error;
10mod kerning_value;
11mod page;
12mod rect;
13mod sections;
14mod string_parse_error;
15mod utils;
16
17pub use self::config_parse_error::ConfigParseError;
18pub use self::error::Error;
19pub use self::rect::Rect;
20pub use self::string_parse_error::StringParseError;
21
22use self::char::Char;
23use self::kerning_value::KerningValue;
24use self::page::Page;
25use self::sections::Sections;
26use std::io::Read;
27use std::iter::Peekable;
28use std::str::Chars;
29
30#[cfg(feature = "parse-error")]
37pub type Parse<'a> = Result<ParseIter<'a>, StringParseError>;
38
39#[cfg(not(feature = "parse-error"))]
46pub type Parse<'a> = ParseIter<'a>;
47
48#[cfg(feature = "parse-error")]
49type ParseLines<'a> = Result<LineIter<'a>, StringParseError>;
50
51#[cfg(not(feature = "parse-error"))]
52type ParseLines<'a> = LineIter<'a>;
53
54#[derive(Clone, Debug)]
55pub struct CharPosition {
56 pub page_rect: Rect,
57 pub screen_rect: Rect,
58 pub page_index: u32,
59}
60
61#[derive(Clone, Debug)]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "serde_json", derive(Eq, PartialEq))]
64pub enum OrdinateOrientation {
65 BottomToTop,
66 TopToBottom,
67}
68
69#[derive(Clone, Debug)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72#[cfg_attr(feature = "serde_json", derive(Eq, PartialEq))]
73pub struct BMFont {
74 base_height: u32,
75 line_height: u32,
76 characters: Vec<Char>,
77 kerning_values: Vec<KerningValue>,
78 pages: Vec<Page>,
79 ordinate_orientation: OrdinateOrientation,
80}
81
82impl BMFont {
83 pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
112 where
113 R: Read,
114 {
115 let sections = Sections::new(source)?;
116
117 let base_height;
118 let line_height;
119 {
120 let mut components = sections.common_section.split_whitespace();
121 components.next();
122 line_height =
123 utils::extract_component_value(components.next(), "common", "lineHeight")?;
124 base_height = utils::extract_component_value(components.next(), "common", "base")?;
125 }
126
127 let mut pages = Vec::with_capacity(sections.page_sections.len());
128 for page_section in §ions.page_sections {
129 pages.push(Page::new(page_section)?);
130 }
131
132 let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
134 for char_section in §ions.char_sections {
135 let char = Char::new(char_section)?;
136 if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
137 characters.insert(idx, char);
138 }
139 }
140
141 let mut kerning_values: Vec<KerningValue> =
143 Vec::with_capacity(sections.kerning_sections.len());
144 for kerning_section in §ions.kerning_sections {
145 let kerning = KerningValue::new(kerning_section)?;
146
147 match kerning_values
148 .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
149 {
150 Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
151 }
152 }
153
154 Ok(BMFont {
155 base_height,
156 line_height,
157 characters,
158 kerning_values,
159 pages,
160 ordinate_orientation,
161 })
162 }
163
164 pub fn base_height(&self) -> u32 {
166 self.base_height
167 }
168
169 pub fn line_height(&self) -> u32 {
170 self.line_height
171 }
172
173 pub fn pages(&self) -> PageIter {
187 PageIter::new(&self.pages)
188 }
189
190 pub fn parse<'s>(&'s self, s: &'s str) -> Parse<'s> {
191 let lines = self.parse_lines(s);
192
193 #[cfg(feature = "parse-error")]
194 let lines = lines?;
195
196 let char_positions = ParseIter::new(self, lines);
197
198 #[cfg(feature = "parse-error")]
199 {
200 Ok(char_positions)
201 }
202
203 #[cfg(not(feature = "parse-error"))]
204 {
205 char_positions
206 }
207 }
208
209 fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
210 let needle = (first_char_id << 1) - 1;
211 let idx = self
212 .kerning_values
213 .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
214 .unwrap_err();
215
216 KerningIter {
217 first_char_id,
218 idx,
219 values: &self.kerning_values,
220 }
221 }
222
223 fn parse_lines<'a>(&'a self, s: &'a str) -> ParseLines<'a> {
224 #[cfg(feature = "parse-error")]
225 {
226 let mut temp = [0u16; 2];
227 let mut missing_characters: Option<Vec<char>> = None;
228 let mut unsupported_characters: Option<Vec<char>> = None;
229
230 for c in s.chars() {
231 if c == '\n' {
232 continue;
233 } else if c.len_utf16() != 1 {
234 if let Some(vec) = unsupported_characters.as_mut() {
235 vec.push(c);
236 } else {
237 unsupported_characters = Some(vec![c]);
238 }
239
240 continue;
241 }
242
243 c.encode_utf16(&mut temp);
244 let char_id = temp[0] as u32;
245
246 if self
247 .characters
248 .binary_search_by(|probe| probe.id.cmp(&char_id))
249 .is_ok()
250 {
251 continue;
252 }
253
254 if let Some(vec) = missing_characters.as_mut() {
255 vec.push(c);
256 } else {
257 missing_characters = Some(vec![c]);
258 }
259 }
260
261 if missing_characters.is_some() || unsupported_characters.is_some() {
262 return Err(StringParseError {
263 missing_characters: missing_characters.unwrap_or_default(),
264 unsupported_characters: unsupported_characters.unwrap_or_default(),
265 });
266 }
267 }
268
269 let lines = LineIter {
270 characters: &self.characters,
271 text: Some(s.chars().peekable()),
272 };
273
274 #[cfg(feature = "parse-error")]
275 {
276 Ok(lines)
277 }
278
279 #[cfg(not(feature = "parse-error"))]
280 lines
281 }
282}
283
284struct CharIter<'a> {
285 characters: &'a Vec<Char>,
286 text: Peekable<Chars<'a>>,
287}
288
289impl<'a> Iterator for CharIter<'a> {
290 type Item = &'a Char;
291
292 fn next(&mut self) -> Option<Self::Item> {
293 loop {
294 return match self.text.next() {
295 None | Some('\n') => None,
296 Some(chr) if chr.len_utf16() != 1 => continue,
297 Some(chr) => {
298 let mut temp = [0u16; 2];
299 chr.encode_utf16(&mut temp);
300 let char_id = temp[0] as u32;
301 let char_idx = self
302 .characters
303 .binary_search_by(|probe| probe.id.cmp(&char_id));
304
305 #[cfg(not(feature = "parse-error"))]
306 if char_idx.is_err() {
307 continue;
308 }
309
310 let char_idx = char_idx.unwrap();
311 Some(&self.characters[char_idx])
312 }
313 };
314 }
315 }
316}
317
318struct KerningIter<'a> {
319 first_char_id: u32,
320 idx: usize,
321 values: &'a Vec<KerningValue>,
322}
323
324impl<'a> KerningIter<'a> {
325 fn empty(values: &'a Vec<KerningValue>) -> Self {
326 Self {
327 first_char_id: 0,
328 idx: values.len(),
329 values,
330 }
331 }
332}
333
334impl<'a> Iterator for KerningIter<'a> {
335 type Item = &'a KerningValue;
336
337 fn next(&mut self) -> Option<Self::Item> {
338 if let Some(value) = self.values.get(self.idx) {
339 if value.first_char_id == self.first_char_id {
340 self.idx += 1;
341
342 return Some(value);
343 }
344 }
345 None
346 }
347}
348
349struct LineIter<'a> {
350 characters: &'a Vec<Char>,
351 text: Option<Peekable<Chars<'a>>>,
352}
353
354impl<'a> Iterator for LineIter<'a> {
355 type Item = CharIter<'a>;
356
357 fn next(&mut self) -> Option<Self::Item> {
358 match self.text.as_mut().unwrap().peek() {
359 Some(_) => Some(CharIter {
360 characters: &self.characters,
361 text: self.text.take().unwrap(),
362 }),
363 _ => None,
364 }
365 }
366}
367
368#[derive(Clone, Debug)]
369pub struct PageIter<'a> {
370 idx: usize,
371 pages: &'a Vec<Page>,
372}
373
374impl<'a> PageIter<'a> {
375 fn new(pages: &'a Vec<Page>) -> Self {
376 Self { idx: 0, pages }
377 }
378}
379
380impl<'a> Iterator for PageIter<'a> {
381 type Item = &'a str;
382
383 fn next(&mut self) -> Option<Self::Item> {
384 if let Some(page) = self.pages.get(self.idx) {
385 self.idx += 1;
386 Some(page.file.as_str())
387 } else {
388 None
389 }
390 }
391}
392
393pub struct ParseIter<'a> {
394 font: &'a BMFont,
395 line: Option<ParseLineIter<'a>>,
396 lines: LineIter<'a>,
397 y: i32,
398}
399
400impl<'a> ParseIter<'a> {
401 fn new(font: &'a BMFont, lines: LineIter<'a>) -> Self {
402 Self {
403 font,
404 line: None,
405 lines,
406 y: 0,
407 }
408 }
409}
410
411impl<'a> Iterator for ParseIter<'a> {
412 type Item = CharPosition;
413
414 fn next(&mut self) -> Option<Self::Item> {
415 loop {
416 if self.line.is_none() {
417 if let Some(chars) = self.lines.next() {
418 self.line = Some(ParseLineIter::new(&self.font, chars, self.y));
419 } else {
420 return None;
421 }
422 }
423
424 let line = self.line.as_mut().unwrap();
425 if let Some(char_position) = line.next() {
426 return Some(char_position);
427 }
428
429 self.lines
430 .text
431 .replace(self.line.take().unwrap().chars.text);
432 match self.font.ordinate_orientation {
433 OrdinateOrientation::TopToBottom => self.y += self.font.line_height as i32,
434 OrdinateOrientation::BottomToTop => self.y -= self.font.line_height as i32,
435 }
436 }
437 }
438}
439
440struct ParseLineIter<'a> {
441 font: &'a BMFont,
442 chars: CharIter<'a>,
443 kerning_values: KerningIter<'a>,
444 x: i32,
445 y: i32,
446}
447
448impl<'a> ParseLineIter<'a> {
449 fn new(font: &'a BMFont, chars: CharIter<'a>, y: i32) -> Self {
450 Self {
451 font,
452 chars,
453 kerning_values: KerningIter::empty(&font.kerning_values),
454 x: 0,
455 y,
456 }
457 }
458}
459
460impl<'a> Iterator for ParseLineIter<'a> {
461 type Item = CharPosition;
462
463 fn next(&mut self) -> Option<Self::Item> {
464 match self.chars.next() {
465 Some(char) => {
466 let kerning_value = self
467 .kerning_values
468 .find(|k| k.second_char_id == char.id)
469 .map(|k| k.value)
470 .unwrap_or(0);
471 let page_rect = Rect {
472 x: char.x as i32,
473 y: char.y as i32,
474 width: char.width,
475 height: char.height,
476 };
477 let screen_x = self.x + char.xoffset + kerning_value;
478 let screen_y = match self.font.ordinate_orientation {
479 OrdinateOrientation::BottomToTop => {
480 self.y + self.font.base_height as i32 - char.yoffset - char.height as i32
481 }
482 OrdinateOrientation::TopToBottom => self.y + char.yoffset,
483 };
484 let screen_rect = Rect {
485 x: screen_x,
486 y: screen_y,
487 width: char.width,
488 height: char.height,
489 };
490 let char_position = CharPosition {
491 page_rect,
492 screen_rect,
493 page_index: char.page_index,
494 };
495 self.x += char.xadvance + kerning_value;
496 self.kerning_values = self.font.find_kerning_values(char.id);
497
498 Some(char_position)
499 }
500 _ => None,
501 }
502 }
503}