Skip to main content

black_grimoire/ecs/components/
text.rs

1use super::super::super::renderer::model::ModelInfo;
2use super::super::super::renderer::{RenderJob, Renderer};
3use super::super::{Entity, EntityManager};
4use super::transformation::TransformationSystem;
5use fnv::FnvHashMap;
6use gamemath::Vec2;
7use gamemath::Vec3;
8use gamemath::Vec4;
9use gl::types::GLuint;
10use std::str::FromStr;
11
12struct TextData {
13    owner: Entity,
14    shader: GLuint,
15    model: ModelInfo,
16    texture_set: usize,
17    character_size: Vec2<f32>,
18    uv_scale: Vec2<f32>,
19    tint: Vec4<f32>,
20    emissive_tint: Vec4<f32>,
21    offset: Vec3<f32>,
22    text: String,
23}
24
25pub struct TextSystem {
26    map: FnvHashMap<Entity, usize>,
27    data: Vec<TextData>,
28}
29
30pub struct TextBuilder<'a> {
31    shader: Option<&'a str>,
32    model: Option<&'a str>,
33    texture_set: Option<(&'a str, &'a str)>,
34    uv_scale: Option<Vec2<f32>>,
35    tint: Option<Vec4<f32>>,
36    emissive_tint: Option<Vec4<f32>>,
37    offset: Option<Vec3<f32>>,
38    text: Option<String>,
39}
40
41impl<'a> TextBuilder<'a> {
42    pub fn new() -> TextBuilder<'a> {
43        TextBuilder {
44            shader: None,
45            model: None,
46            texture_set: None,
47            uv_scale: None,
48            tint: None,
49            emissive_tint: None,
50            offset: None,
51            text: None,
52        }
53    }
54
55    pub fn using_shader(mut self, shader_name: &'a str) -> TextBuilder {
56        self.shader = Some(shader_name);
57        self
58    }
59
60    pub fn using_model(mut self, model_name: &'a str) -> TextBuilder {
61        self.model = Some(model_name);
62        self
63    }
64
65    pub fn using_texture_set(mut self, albedo: &'a str, emissive: &'a str) -> TextBuilder<'a> {
66        self.texture_set = Some((albedo, emissive));
67        self
68    }
69
70    pub fn with_uv_scale(mut self, uv_scale: Vec2<f32>) -> TextBuilder<'a> {
71        self.uv_scale = Some(uv_scale);
72        self
73    }
74
75    pub fn with_tint(mut self, tint: Vec4<f32>) -> TextBuilder<'a> {
76        self.tint = Some(tint);
77        self
78    }
79
80    pub fn with_emissive_tint(mut self, tint: Vec4<f32>) -> TextBuilder<'a> {
81        self.emissive_tint = Some(tint);
82        self
83    }
84
85    pub fn with_text(mut self, text: String) -> TextBuilder<'a> {
86        self.text = Some(text);
87        self
88    }
89
90    pub fn with_offset(mut self, offset: Vec3<f32>) -> TextBuilder<'a> {
91        self.offset = Some(offset);
92        self
93    }
94
95    fn build(self, owner: Entity, renderer: &mut Renderer<'a>) -> TextData {
96        let mut new_text = TextData {
97            owner,
98            shader: match self.shader {
99                Some(s) => renderer.get_shader(s).unwrap(),
100                None => renderer.get_shader("test").unwrap(),
101            },
102            model: match self.model {
103                Some(m) => renderer.get_model(m).unwrap(),
104                None => renderer.get_model("cube").unwrap(),
105            },
106            texture_set: match self.texture_set {
107                Some(t) => renderer.get_texture_set(t.0, t.1),
108                None => renderer.get_texture_set("font.png", "black.png"),
109            },
110            character_size: Vec2::new(0.0, 0.0),
111            uv_scale: match self.uv_scale {
112                Some(s) => s,
113                None => Vec2::new(1.0, 1.0),
114            },
115            tint: match self.tint {
116                Some(t) => t,
117                None => Vec4::new(1.0, 1.0, 1.0, 1.0),
118            },
119            emissive_tint: match self.emissive_tint {
120                Some(t) => t,
121                None => Vec4::new(0.0, 0.0, 0.0, 0.0),
122            },
123            offset: match self.offset {
124                Some(o) => o,
125                None => Vec3::new(0.0, 0.0, 0.0),
126            },
127            text: match self.text {
128                Some(t) => t,
129                None => String::from_str("Text").unwrap(),
130            },
131        };
132
133        let sizes = renderer.get_texture_set_sizes(new_text.texture_set);
134
135        new_text.character_size = Vec2::new(sizes.0.x / 10.0, sizes.0.y / 10.0);
136
137        new_text.character_size = Vec2::new(6.0, 6.0);
138
139        new_text
140    }
141}
142
143impl<'a> TextSystem {
144    pub fn new() -> TextSystem {
145        TextSystem {
146            map: FnvHashMap::with_capacity_and_hasher(1, Default::default()),
147            data: Vec::new(),
148        }
149    }
150
151    pub fn add_text_to_entity(
152        &mut self,
153        entity: &Entity,
154        transformation_system: &TransformationSystem,
155        renderer: &mut Renderer<'a>,
156        initial_data: TextBuilder<'a>,
157    ) {
158        match self.map.contains_key(entity) {
159            true => (), //TODO: Add error logging/printing here!
160            false => {
161                match transformation_system.entity_has_transformation(entity) {
162                    true => {
163                        self.data.push(initial_data.build(*entity, renderer));
164                        self.map.insert(entity.clone(), self.data.len() - 1);
165                    }
166                    false => (), //TODO: Add error logging/printing here!
167                }
168            }
169        }
170    }
171
172    pub fn remove_text_from_entity(&mut self, entity: &Entity) {
173        let mut swapped = (false, 0);
174        let mut removed = false;
175
176        if *entity != Entity::null() {
177            match self.map.get(entity) {
178                Some(index) => {
179                    self.data.swap_remove(*index);
180                    removed = true;
181
182                    if self.data.is_empty() == false {
183                        swapped = (true, *index);
184                    }
185                }
186                None => (),
187            }
188        }
189
190        if removed == true {
191            self.map.remove(entity);
192        }
193
194        if swapped.0 == true && swapped.1 != self.data.len() {
195            *self.map.get_mut(&self.data[swapped.1].owner).unwrap() = swapped.1;
196        }
197    }
198
199    pub fn entity_has_text(&self, entity: &Entity) -> bool {
200        self.map.contains_key(entity)
201    }
202
203    pub fn set_tint_color(&mut self, entity: &Entity, color: Vec4<f32>) {
204        if *entity != Entity::null() {
205            match self.map.get(entity) {
206                Some(index) => {
207                    self.data[*index].tint = color;
208                }
209                None => (),
210            }
211        }
212    }
213
214    pub fn set_text(&mut self, entity: &Entity, text: &str) {
215        if *entity != Entity::null() {
216            match self.map.get(entity) {
217                Some(index) => {
218                    self.data[*index].text = String::from_str(text).unwrap();
219                }
220                None => (),
221            }
222        }
223    }
224
225    pub fn draw_all(
226        &self,
227        entity_manager: &EntityManager,
228        transformation_system: &TransformationSystem,
229        renderer: &mut Renderer,
230    ) {
231        for text in self.data.iter() {
232            if entity_manager.entity_is_active(&text.owner) == true {
233                let t = transformation_system
234                    .get_transformation_data(&text.owner)
235                    .unwrap();
236                let uv_size = Vec2::new(0.1, 0.1);
237                let mut uv = Vec2::new(0.0, 0.0);
238                let mut character_position = t.position;
239
240                for c in text.text.chars() {
241                    match c {
242                        'a' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 1.0),
243                        'b' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 1.0),
244                        'c' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 1.0),
245                        'd' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 1.0),
246                        'e' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 1.0),
247                        'f' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 1.0),
248                        'g' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 1.0),
249                        'h' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 1.0),
250                        'i' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 1.0),
251                        'j' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 1.0),
252                        'k' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 2.0),
253                        'l' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 2.0),
254                        'm' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 2.0),
255                        'n' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 2.0),
256                        'o' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 2.0),
257                        'p' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 2.0),
258                        'q' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 2.0),
259                        'r' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 2.0),
260                        's' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 2.0),
261                        't' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 2.0),
262                        'u' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 3.0),
263                        'v' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 3.0),
264                        'w' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 3.0),
265                        'x' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 3.0),
266                        'y' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 3.0),
267                        'z' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 3.0),
268                        ',' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 3.0),
269                        '.' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 3.0),
270                        ':' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 3.0),
271                        ';' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 3.0),
272                        'A' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 4.0),
273                        'B' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 4.0),
274                        'C' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 4.0),
275                        'D' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 4.0),
276                        'E' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 4.0),
277                        'F' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 4.0),
278                        'G' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 4.0),
279                        'H' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 4.0),
280                        'I' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 4.0),
281                        'J' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 4.0),
282                        'K' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 5.0),
283                        'L' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 5.0),
284                        'M' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 5.0),
285                        'N' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 5.0),
286                        'O' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 5.0),
287                        'P' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 5.0),
288                        'Q' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 5.0),
289                        'R' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 5.0),
290                        'S' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 5.0),
291                        'T' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 5.0),
292                        'U' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 6.0),
293                        'V' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 6.0),
294                        'W' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 6.0),
295                        'X' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 6.0),
296                        'Y' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 6.0),
297                        'Z' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 6.0),
298                        '!' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 6.0),
299                        '?' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 6.0),
300                        '\'' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 6.0),
301                        '"' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 6.0),
302                        '0' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 7.0),
303                        '1' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 7.0),
304                        '2' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 7.0),
305                        '3' => uv = Vec2::new(uv_size.x * 3.0, uv_size.y * 7.0),
306                        '4' => uv = Vec2::new(uv_size.x * 4.0, uv_size.y * 7.0),
307                        '5' => uv = Vec2::new(uv_size.x * 5.0, uv_size.y * 7.0),
308                        '6' => uv = Vec2::new(uv_size.x * 6.0, uv_size.y * 7.0),
309                        '7' => uv = Vec2::new(uv_size.x * 7.0, uv_size.y * 7.0),
310                        '8' => uv = Vec2::new(uv_size.x * 8.0, uv_size.y * 7.0),
311                        '9' => uv = Vec2::new(uv_size.x * 9.0, uv_size.y * 7.0),
312                        '-' => uv = Vec2::new(uv_size.x * 0.0, uv_size.y * 8.0),
313                        '+' => uv = Vec2::new(uv_size.x * 1.0, uv_size.y * 8.0),
314                        '%' => uv = Vec2::new(uv_size.x * 2.0, uv_size.y * 8.0),
315                        '\n' => {
316                            character_position.x = t.position.x;
317                            character_position.y -= text.character_size.y + 1.0;
318                            continue;
319                        }
320                        ' ' => {
321                            character_position.x += text.character_size.x * 2.0 + 2.0;
322                            continue;
323                        }
324                        _ => continue,
325                    }
326
327                    renderer.add_render_job(RenderJob {
328                        model: text.model,
329                        shader: text.shader,
330                        textures: text.texture_set,
331                        scale: Vec3::new(text.character_size.x, text.character_size.y, 1.0),
332                        uv_size,
333                        uv_offset: uv,
334                        position: character_position + text.offset,
335                        pivot: t.pivot,
336                        rotation: t.rotation,
337                        tint: text.tint,
338                        emissive_tint: text.emissive_tint,
339                    });
340
341                    character_position.x += text.character_size.x * 2.0 + 2.0;
342                }
343            }
344        }
345    }
346}