3d5d73cfcf92688095d43f2fb30c7e1d2512887a
[mandelwow.git] / text.rs
1 use cgmath::conv::array4x4;
2 use cgmath::{Matrix4, Vector3};
3 use glium;
4 use glium::{Display, Program, Surface, implement_vertex, texture, uniform};
5 use std;
6
7 fn gamma<T>(x: T) -> f32
8 where
9     f32: From<T>,
10     T: Copy,
11 {
12     ((f32::from(x)) / 255.).powf(2.2)
13 }
14
15 fn srgb<T>(c: [T; 3]) -> [f32; 4]
16 where
17     f32: From<T>,
18     T: Copy,
19 {
20     [gamma(c[0]), gamma(c[1]), gamma(c[2]), 0.0]
21 }
22
23 #[cfg(feature = "image")]
24 fn c64_font() -> (u32, u32, Vec<u8>) {
25     let image = image::load_from_memory_with_format(
26         &include_bytes!("textures/c64-font.png")[..],
27         image::PNG,
28     ).unwrap()
29         .to_luma();
30     let (w, h) = image.dimensions();
31     (w, h, image.into_raw())
32 }
33
34 #[cfg(not(feature = "image"))]
35 fn c64_font() -> (u32, u32, Vec<u8>) {
36     let pixels = &include_bytes!("textures/c64-font.gray")[..];
37     (128, 128, Vec::from(pixels))
38 }
39
40 pub fn text_program(display: &Display) -> Program {
41     //load_program(display, "shaders/text.vert", "shaders/text.frag");
42     let vertex_shader_src = include_str!("shaders/text.vert");
43     let fragment_shader_src = include_str!("shaders/text.frag");
44     Program::from_source(display, vertex_shader_src, fragment_shader_src, None).unwrap()
45 }
46
47 #[derive(Copy, Clone)]
48 struct Vertex {
49     position: [f32; 2],
50     tex_coords: [f32; 2],
51 }
52 implement_vertex!(Vertex, position, tex_coords);
53
54 pub struct Text<'a> {
55     tex: texture::Texture2d,
56     vertex_buffer: glium::VertexBuffer<Vertex>,
57     index_buffer: glium::IndexBuffer<u16>,
58     program: glium::Program,
59     params: glium::DrawParameters<'a>,
60     pub model: Matrix4<f32>,
61     pub character: char,
62 }
63
64 impl<'a> Text<'a> {
65     pub fn new(display: &Display, character: char) -> Text<'_> {
66         let (w, h, pixels) = c64_font();
67         let image = glium::texture::RawImage2d {
68             data: std::borrow::Cow::from(pixels),
69             width: w,
70             height: h,
71             format: glium::texture::ClientFormat::U8,
72         };
73         let tex = glium::texture::Texture2d::with_format(
74             display,
75             image,
76             glium::texture::UncompressedFloatFormat::U8,
77             glium::texture::MipmapsOption::NoMipmap,
78         ).unwrap();
79
80         // building the vertex buffer, which contains all the vertices that we will draw
81         let vertex_buffer = {
82             glium::VertexBuffer::new(
83                 display,
84                 &[
85                     Vertex {
86                         position: [-0.5, -0.5],
87                         tex_coords: [0.0, 1.0],
88                     },
89                     Vertex {
90                         position: [-0.5, 0.5],
91                         tex_coords: [0.0, 0.0],
92                     },
93                     Vertex {
94                         position: [0.5, 0.5],
95                         tex_coords: [1.0, 0.0],
96                     },
97                     Vertex {
98                         position: [0.5, -0.5],
99                         tex_coords: [1.0, 1.0],
100                     },
101                 ],
102             ).unwrap()
103         };
104
105         let index_buffer = glium::IndexBuffer::new(
106             display,
107             glium::index::PrimitiveType::TriangleStrip,
108             &[1 as u16, 2, 0, 3],
109         ).unwrap();
110
111         let params = glium::DrawParameters {
112             depth: glium::Depth {
113                 test: glium::draw_parameters::DepthTest::IfLess,
114                 write: true,
115                 ..Default::default()
116             },
117             multisampling: true,
118             ..Default::default()
119         };
120
121         Text {
122             tex: tex,
123             vertex_buffer: vertex_buffer,
124             index_buffer: index_buffer,
125             program: text_program(display),
126             params: params,
127             model: Matrix4::from_translation(Vector3::unit_z() * (-1.0)),
128             character: character,
129         }
130     }
131
132     pub fn draw(&self, frame: &mut glium::Frame, perspview: &[[f32; 4]; 4]) {
133         let uniforms =
134             uniform! {
135             model: array4x4(self.model),
136             perspview: *perspview,
137             tex: self.tex.sampled()
138                 .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
139             index: self.character as i32,
140             // RGB values from http://unusedino.de/ec64/technical/misc/vic656x/colors/
141             bgcolor: srgb([ 64,  50, 133u8]),  //  6 - blue
142             fgcolor: srgb([120, 106, 189u8]),  // 14 - light blue
143         };
144         frame
145             .draw(
146                 &self.vertex_buffer,
147                 &self.index_buffer,
148                 &self.program,
149                 &uniforms,
150                 &self.params,
151             )
152             .unwrap();
153     }
154 }