Move text rendering shaders out of line.
[mandelwow.git] / text.rs
1 use cgmath::conv::array4x4;
2 use cgmath::{Matrix4, Vector3};
3 use glium;
4 use glium::{Display, Program, Surface, texture};
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     use image;
26     let image = image::load_from_memory_with_format(
27         &include_bytes!("textures/c64-font.png")[..],
28         image::PNG,
29     ).unwrap()
30         .to_luma();
31     let (w, h) = image.dimensions();
32     (w, h, image.into_raw())
33 }
34
35 #[cfg(not(feature = "image"))]
36 fn c64_font() -> (u32, u32, Vec<u8>) {
37     let pixels = &include_bytes!("textures/c64-font.gray")[..];
38     (128, 128, Vec::from(pixels))
39 }
40
41 pub fn text_program(display: &Display) -> Program {
42     //load_program(display, "shaders/text.vert", "shaders/text.frag");
43     let vertex_shader_src = include_str!("shaders/text.vert");
44     let fragment_shader_src = include_str!("shaders/text.frag");
45     Program::from_source(display, vertex_shader_src, fragment_shader_src, None).unwrap()
46 }
47
48 #[derive(Copy, Clone)]
49 struct Vertex {
50     position: [f32; 2],
51     tex_coords: [f32; 2],
52 }
53 implement_vertex!(Vertex, position, tex_coords);
54
55 pub struct Text<'a> {
56     tex: texture::Texture2d,
57     vertex_buffer: glium::VertexBuffer<Vertex>,
58     index_buffer: glium::IndexBuffer<u16>,
59     program: glium::Program,
60     params: glium::DrawParameters<'a>,
61     model: Matrix4<f32>,
62 }
63
64 impl<'a> Text<'a> {
65     pub fn new(display: &Display) -> 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: [-1.0, -1.0],
87                         tex_coords: [0.0, 1.0],
88                     },
89                     Vertex {
90                         position: [-1.0, 1.0],
91                         tex_coords: [0.0, 0.0],
92                     },
93                     Vertex {
94                         position: [1.0, 1.0],
95                         tex_coords: [1.0, 0.0],
96                     },
97                     Vertex {
98                         position: [1.0, -1.0],
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             model: Matrix4::from_translation(Vector3::unit_z() * (-1.0)),
123             tex: tex,
124             vertex_buffer: vertex_buffer,
125             index_buffer: index_buffer,
126             program: text_program(display),
127             params: params,
128         }
129     }
130
131     pub fn draw(&self, frame: &mut glium::Frame, perspview: &[[f32; 4]; 4]) {
132         let uniforms =
133             uniform! {
134             model: array4x4(self.model),
135             perspview: *perspview,
136             tex: self.tex.sampled()
137                 .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
138             index: 'C' as i32,
139             // RGB values from http://unusedino.de/ec64/technical/misc/vic656x/colors/
140             bgcolor: srgb([ 64,  50, 133u8]),  //  6 - blue
141             fgcolor: srgb([120, 106, 189u8]),  // 14 - light blue
142         };
143         frame
144             .draw(
145                 &self.vertex_buffer,
146                 &self.index_buffer,
147                 &self.program,
148                 &uniforms,
149                 &self.params,
150             )
151             .unwrap();
152     }
153 }