Skip to main content

gust_render/
text.rs

1//
2//  Rust file | 2018
3//  Author: Alexandre Fourcat
4//  text.rs
5//  module:
6//! text render utils
7use color::Color;
8use draw::{BlendMode, Context, Drawable, DrawableMut, Drawer, IDENTITY};
9use font::{CharInfo, Font};
10use nalgebra::Scalar;
11use shader;
12use std::cell::RefCell;
13use std::{error::Error, rc::Rc};
14/// # How to use
15/// ```no_run
16/// use gust::text::Text;
17/// use gust::font::Font;
18/// use gust::window::Window;
19///
20/// fn draw(score: u32) {
21///     let window = Default::default();
22///     let arial = MutResource::new(Font::from_path("resources/font/arial.ttf"));
23///     let score = Text::new(&arial);
24///
25///     score.set_content(format!("Score: {}", score));
26///     score.set_position(Vector::new(10.0, 10.0));
27///     while window.is_open() {
28///         window.clear();
29///         window.draw(&score);
30///         window.display();
31///     }
32/// }
33/// ```
34/// It's made from the Text system of the C++ library SFML.
35use texture::Texture;
36use transform::*;
37use vertex::Vertex;
38use vertex_buffer::VertexBuffer;
39use {Point, Vector};
40
41extern crate freetype as ft;
42
43#[derive(Debug)]
44/// # Text struct
45/// Text is a drawable entity that can be used to display text.
46/// The text need a MutResource<Font> because the text mut the
47/// internal texture of his font.
48pub struct Text {
49    font: Rc<RefCell<Font>>,
50    content: String,
51    actual_size: u32,
52    vertex_buffer: VertexBuffer,
53    need_update: bool,
54    pos: Vector<f32>,
55}
56
57impl Text {
58    /// Dump the font texture to a file
59    pub fn dump_texture(&mut self) -> Result<(), Box<Error>> {
60        // Get the texture
61        let font_ref = self.font.try_borrow().unwrap();
62        let texture = font_ref.texture(self.actual_size).unwrap();
63
64        texture.to_file("font_dump.png")?;
65        Ok(())
66    }
67
68    /// Create a new text from a font previously created
69    pub fn new(font: &Rc<RefCell<Font>>) -> Text {
70        Text {
71            font: Rc::clone(font),
72            content: String::new(),
73            actual_size: 14,
74            vertex_buffer: VertexBuffer::default(),
75            need_update: true,
76            pos: Vector::new(0.0, 0.0),
77        }
78    }
79
80    /// Create a text from it's content and a font
81    pub fn from_str(font: &Rc<RefCell<Font>>, content: &str) -> Text {
82        Text {
83            font: Rc::clone(font),
84            content: String::from(content),
85            actual_size: 14,
86            vertex_buffer: VertexBuffer::default(),
87            need_update: true,
88            pos: Vector::new(0.0, 0.0),
89        }
90    }
91
92    /// Set the content of the text
93    pub fn set_content(&mut self, content: &str) {
94        self.content = String::from(content);
95        self.need_update = true;
96    }
97
98    /// Get the content of the text as &String
99    pub fn content(&self) -> &String {
100        &self.content
101    }
102
103    /// Get the content of the text as &mut String
104    pub fn content_mut(&mut self) -> &mut String {
105        self.need_update = true;
106        &mut self.content
107    }
108
109    /// Set the local font size
110    pub fn set_size(&mut self, size: u32) {
111        self.actual_size = size;
112        self.need_update = true;
113    }
114
115    /// Get the local font size
116    pub fn size(&self) -> u32 {
117        self.actual_size
118    }
119
120    fn set_texture(&mut self, _texture: &Rc<Texture>) {
121        unimplemented!();
122    }
123}
124
125impl Transformable for Text {
126    fn contain<T>(&self, _point: Point<T>) -> bool
127    where
128        T: Scalar + Into<f32>,
129    {
130        true
131    }
132
133    fn set_origin<T>(&mut self, _origin: Vector<T>)
134    where
135        T: Scalar + Into<f32>,
136    {
137        unimplemented!();
138    }
139
140    fn get_origin(&self) -> Vector<f32> {
141        Vector::new(0.0, 0.0)
142    }
143}
144
145impl Scalable for Text {
146    fn scale<T>(&mut self, _factor: Vector<T>)
147    where
148        T: Scalar + Into<f32>,
149    {
150        unimplemented!();
151    }
152
153    fn set_scale<T>(&mut self, _vec: Vector<T>)
154    where
155        T: Scalar + Into<f32>,
156    {
157        unimplemented!();
158    }
159
160    fn get_scale(&self) -> Vector<f32> {
161        unimplemented!();
162    }
163}
164
165impl Rotable for Text {
166    fn rotate<T>(&mut self, _angle: T)
167    where
168        T: Scalar + Into<f32>,
169    {
170        unimplemented!();
171    }
172
173    fn set_rotation<T>(&mut self, _angle: T)
174    where
175        T: Scalar + Into<f32>,
176    {
177        unimplemented!();
178    }
179
180    fn get_rotation(&self) -> f32 {
181        0.0
182    }
183}
184
185impl Movable for Text {
186    fn translate<T>(&mut self, offset: Vector<T>)
187    where
188        T: Scalar + Into<f32>,
189    {
190        self.pos.x += offset.x.into();
191        self.pos.y += offset.y.into();
192        self.need_update = true;
193    }
194
195    fn set_position<T>(&mut self, pos: Vector<T>)
196    where
197        T: Scalar + Into<f32>,
198    {
199        self.pos.x = pos.x.into();
200        self.pos.y = pos.y.into();
201        self.need_update = true;
202    }
203
204    fn get_position(&self) -> Vector<f32> {
205        self.pos
206    }
207}
208
209impl DrawableMut for Text {
210    fn draw_mut<T: Drawer>(&mut self, target: &mut T) {
211        self.update();
212        self.draw(target);
213    }
214
215    fn draw_with_context_mut(&mut self, context: &mut Context) {
216        self.update();
217        self.draw_with_context(context);
218    }
219}
220
221impl Drawable for Text {
222    fn update(&mut self) {
223        // Si l'update n'est pas necessaire
224        if !self.need_update {
225            return;
226        }
227
228        // Relative position
229        let mut pos = self.pos;
230        let mut offset = 0.0;
231
232        // Get reference to the font that is a reference counter
233        let mut font_ref = self.font.try_borrow_mut().unwrap();
234
235        // Get the whitespace x size
236        let whitespace;
237        let height;
238        {
239            let space_glyph = font_ref.glyph(self.actual_size, 0x20_u32);
240            whitespace = space_glyph.advance;
241        }
242        {
243            let a_glyph = font_ref.glyph(self.actual_size, 0x41_u32);
244            height = a_glyph.rect.height + a_glyph.rect.height / 5.0;
245        }
246
247        // Setup padding
248        let padding = 0.0;
249
250        // Clear the buffer of the data
251        self.vertex_buffer.clear();
252
253        // Iter of character of the content to create a geometry for each one of them
254        for charr in self.content.as_str().chars() {
255            // If the char is a special one
256            match charr {
257                '\n' => {
258                    pos.y += height;
259                    offset = 0.0;
260                    continue;
261                }
262                '\r' => continue,
263                '\t' => {
264                    offset += 4.0 * whitespace;
265                    continue;
266                }
267                ' ' => {
268                    offset += whitespace;
269                    continue;
270                }
271                _ => {}
272            };
273
274            // Get the glyph from the the font
275            let char_info = font_ref.glyph(self.actual_size, charr as u32);
276
277            // get vertices from char_info
278            let vertices = get_vertice_letter(&char_info, pos, padding, offset);
279
280            // append vertice to vertex_buffer
281            self.vertex_buffer.append(&vertices);
282
283            // x position of the character
284            offset += char_info.advance as f32;
285        }
286        // Update final buffer
287        self.vertex_buffer.update();
288
289        // Set to false the boolean that contral this function
290        self.need_update = false;
291    }
292
293    fn draw<T: Drawer>(&self, target: &mut T) {
294        // If there is no text don't draw
295        if self.content.is_empty() {
296            return;
297        }
298
299        // Get the texture
300        let font_ref = self.font.try_borrow().unwrap();
301        let texture = font_ref.texture(self.actual_size).unwrap();
302
303        // Create a new context with the Texture of the font
304        let mut context = Context::new(
305            Some(texture),
306            &*shader::DEFAULT_SHADER,
307            vec![
308                ("transform".to_string(), &*IDENTITY),
309                ("projection".to_string(), target.projection()),
310            ],
311            BlendMode::Alpha,
312        );
313
314        // Draw the vertex_buffer with context
315        self.vertex_buffer.draw_with_context(&mut context);
316    }
317
318    fn draw_with_context(&self, context: &mut Context) {
319        self.vertex_buffer.draw_with_context(context);
320    }
321}
322
323/// Get a vertice from a character information, padding and offset
324fn get_vertice_letter(
325    char_info: &CharInfo,
326    pos: Vector<f32>,
327    padding: f32,
328    offset: f32,
329) -> [Vertex; 6] {
330    let x = pos.x + offset;
331    let y = pos.y;
332
333    // Set geometry for 1 character
334    let left = char_info.rect.left - padding;
335    let top = char_info.rect.top - padding;
336    let right = char_info.rect.left + char_info.rect.width + padding;
337    let bottom = char_info.rect.top + char_info.rect.height + padding;
338
339    // Set texture coord for each character
340    let u1 = ((char_info.tex_coord.left - padding as u32) as f32) / 128.0;
341    let v1 = ((char_info.tex_coord.top - padding as u32) as f32) / 128.0;
342    let u2 =
343        ((char_info.tex_coord.left + char_info.tex_coord.width + padding as u32) as f32) / 128.0;
344    let v2 =
345        ((char_info.tex_coord.top + char_info.tex_coord.height + padding as u32) as f32) / 128.0;
346
347    [
348        Vertex::new(
349            Vector::new(x + left, y + top),
350            Vector::new(u1, v1),
351            Color::white(),
352        ),
353        Vertex::new(
354            Vector::new(x + left, y + bottom),
355            Vector::new(u1, v2),
356            Color::white(),
357        ),
358        Vertex::new(
359            Vector::new(x + right, y + bottom),
360            Vector::new(u2, v2),
361            Color::white(),
362        ),
363        Vertex::new(
364            Vector::new(x + left, y + top),
365            Vector::new(u1, v1),
366            Color::white(),
367        ),
368        Vertex::new(
369            Vector::new(x + right, y + bottom),
370            Vector::new(u2, v2),
371            Color::white(),
372        ),
373        Vertex::new(
374            Vector::new(x + right, y + top),
375            Vector::new(u2, v1),
376            Color::white(),
377        ),
378    ]
379}