use color::Color;
use draw::{BlendMode, Context, Drawable, DrawableMut, Drawer, IDENTITY};
use font::{CharInfo, Font};
use nalgebra::Scalar;
use shader;
use std::cell::RefCell;
use std::{error::Error, rc::Rc};
use texture::Texture;
use transform::*;
use vertex::Vertex;
use vertex_buffer::VertexBuffer;
use {Point, Vector};
extern crate freetype as ft;
#[derive(Debug)]
pub struct Text {
font: Rc<RefCell<Font>>,
content: String,
actual_size: u32,
vertex_buffer: VertexBuffer,
need_update: bool,
pos: Vector<f32>,
}
impl Text {
pub fn dump_texture(&mut self) -> Result<(), Box<Error>> {
let font_ref = self.font.try_borrow().unwrap();
let texture = font_ref.texture(self.actual_size).unwrap();
texture.to_file("font_dump.png")?;
Ok(())
}
pub fn new(font: &Rc<RefCell<Font>>) -> Text {
Text {
font: Rc::clone(font),
content: String::new(),
actual_size: 14,
vertex_buffer: VertexBuffer::default(),
need_update: true,
pos: Vector::new(0.0, 0.0),
}
}
pub fn from_str(font: &Rc<RefCell<Font>>, content: &str) -> Text {
Text {
font: Rc::clone(font),
content: String::from(content),
actual_size: 14,
vertex_buffer: VertexBuffer::default(),
need_update: true,
pos: Vector::new(0.0, 0.0),
}
}
pub fn set_content(&mut self, content: &str) {
self.content = String::from(content);
self.need_update = true;
}
pub fn content(&self) -> &String {
&self.content
}
pub fn content_mut(&mut self) -> &mut String {
self.need_update = true;
&mut self.content
}
pub fn set_size(&mut self, size: u32) {
self.actual_size = size;
self.need_update = true;
}
pub fn size(&self) -> u32 {
self.actual_size
}
fn set_texture(&mut self, _texture: &Rc<Texture>) {
unimplemented!();
}
}
impl Transformable for Text {
fn contain<T>(&self, _point: Point<T>) -> bool
where
T: Scalar + Into<f32>,
{
true
}
fn set_origin<T>(&mut self, _origin: Vector<T>)
where
T: Scalar + Into<f32>,
{
unimplemented!();
}
fn get_origin(&self) -> Vector<f32> {
Vector::new(0.0, 0.0)
}
}
impl Scalable for Text {
fn scale<T>(&mut self, _factor: Vector<T>)
where
T: Scalar + Into<f32>,
{
unimplemented!();
}
fn set_scale<T>(&mut self, _vec: Vector<T>)
where
T: Scalar + Into<f32>,
{
unimplemented!();
}
fn get_scale(&self) -> Vector<f32> {
unimplemented!();
}
}
impl Rotable for Text {
fn rotate<T>(&mut self, _angle: T)
where
T: Scalar + Into<f32>,
{
unimplemented!();
}
fn set_rotation<T>(&mut self, _angle: T)
where
T: Scalar + Into<f32>,
{
unimplemented!();
}
fn get_rotation(&self) -> f32 {
0.0
}
}
impl Movable for Text {
fn translate<T>(&mut self, offset: Vector<T>)
where
T: Scalar + Into<f32>,
{
self.pos.x += offset.x.into();
self.pos.y += offset.y.into();
self.need_update = true;
}
fn set_position<T>(&mut self, pos: Vector<T>)
where
T: Scalar + Into<f32>,
{
self.pos.x = pos.x.into();
self.pos.y = pos.y.into();
self.need_update = true;
}
fn get_position(&self) -> Vector<f32> {
self.pos
}
}
impl DrawableMut for Text {
fn draw_mut<T: Drawer>(&mut self, target: &mut T) {
self.update();
self.draw(target);
}
fn draw_with_context_mut(&mut self, context: &mut Context) {
self.update();
self.draw_with_context(context);
}
}
impl Drawable for Text {
fn update(&mut self) {
if !self.need_update {
return;
}
let mut pos = self.pos;
let mut offset = 0.0;
let mut font_ref = self.font.try_borrow_mut().unwrap();
let whitespace;
let height;
{
let space_glyph = font_ref.glyph(self.actual_size, 0x20_u32);
whitespace = space_glyph.advance;
}
{
let a_glyph = font_ref.glyph(self.actual_size, 0x41_u32);
height = a_glyph.rect.height + a_glyph.rect.height / 5.0;
}
let padding = 0.0;
self.vertex_buffer.clear();
for charr in self.content.as_str().chars() {
match charr {
'\n' => {
pos.y += height;
offset = 0.0;
continue;
}
'\r' => continue,
'\t' => {
offset += 4.0 * whitespace;
continue;
}
' ' => {
offset += whitespace;
continue;
}
_ => {}
};
let char_info = font_ref.glyph(self.actual_size, charr as u32);
let vertices = get_vertice_letter(&char_info, pos, padding, offset);
self.vertex_buffer.append(&vertices);
offset += char_info.advance as f32;
}
self.vertex_buffer.update();
self.need_update = false;
}
fn draw<T: Drawer>(&self, target: &mut T) {
if self.content.is_empty() {
return;
}
let font_ref = self.font.try_borrow().unwrap();
let texture = font_ref.texture(self.actual_size).unwrap();
let mut context = Context::new(
Some(texture),
&*shader::DEFAULT_SHADER,
vec![
("transform".to_string(), &*IDENTITY),
("projection".to_string(), target.projection()),
],
BlendMode::Alpha,
);
self.vertex_buffer.draw_with_context(&mut context);
}
fn draw_with_context(&self, context: &mut Context) {
self.vertex_buffer.draw_with_context(context);
}
}
fn get_vertice_letter(
char_info: &CharInfo,
pos: Vector<f32>,
padding: f32,
offset: f32,
) -> [Vertex; 6] {
let x = pos.x + offset;
let y = pos.y;
let left = char_info.rect.left - padding;
let top = char_info.rect.top - padding;
let right = char_info.rect.left + char_info.rect.width + padding;
let bottom = char_info.rect.top + char_info.rect.height + padding;
let u1 = ((char_info.tex_coord.left - padding as u32) as f32) / 128.0;
let v1 = ((char_info.tex_coord.top - padding as u32) as f32) / 128.0;
let u2 =
((char_info.tex_coord.left + char_info.tex_coord.width + padding as u32) as f32) / 128.0;
let v2 =
((char_info.tex_coord.top + char_info.tex_coord.height + padding as u32) as f32) / 128.0;
[
Vertex::new(
Vector::new(x + left, y + top),
Vector::new(u1, v1),
Color::white(),
),
Vertex::new(
Vector::new(x + left, y + bottom),
Vector::new(u1, v2),
Color::white(),
),
Vertex::new(
Vector::new(x + right, y + bottom),
Vector::new(u2, v2),
Color::white(),
),
Vertex::new(
Vector::new(x + left, y + top),
Vector::new(u1, v1),
Color::white(),
),
Vertex::new(
Vector::new(x + right, y + bottom),
Vector::new(u2, v2),
Color::white(),
),
Vertex::new(
Vector::new(x + right, y + top),
Vector::new(u2, v1),
Color::white(),
),
]
}