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 => (), 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 => (), }
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}