Use a regular float texture for the font.
[mandelwow.git] / text.rs
1 use cgmath::conv::array4x4;
2 use cgmath::{Matrix4, One};
3 use glium;
4 use glium::{Surface, texture};
5 use image;
6 use std;
7
8 #[derive(Copy, Clone)]
9 struct Vertex {
10     position: [f32; 2],
11     tex_coords: [f32; 2],
12 }
13 implement_vertex!(Vertex, position, tex_coords);
14
15 pub struct Text<'a> {
16     tex: texture::Texture2d,
17     vertex_buffer: glium::VertexBuffer<Vertex>,
18     index_buffer: glium::IndexBuffer<u16>,
19     program: glium::Program,
20     params: glium::DrawParameters<'a>,
21     model: Matrix4<f32>,
22 }
23
24 impl<'a> Text<'a> {
25     pub fn new(display: &glium::Display) -> Text {
26         let image =
27             image::load_from_memory_with_format(&include_bytes!("c64-font.png")[..], image::PNG)
28                 .unwrap()
29                 .to_luma();
30         let (w, h) = image.dimensions();
31         let image = glium::texture::RawImage2d {
32             data: std::borrow::Cow::from(image.into_raw()),
33             width: w,
34             height: h,
35             format: glium::texture::ClientFormat::U8,
36         };
37         let tex = glium::texture::Texture2d::with_format(
38             display,
39             image,
40             glium::texture::UncompressedFloatFormat::U8,
41             glium::texture::MipmapsOption::NoMipmap,
42         ).unwrap();
43
44         // building the vertex buffer, which contains all the vertices that we will draw
45         let vertex_buffer = {
46             glium::VertexBuffer::new(
47                 display,
48                 &[
49                     Vertex {
50                         position: [-1.0, -1.0],
51                         tex_coords: [0.0, 1.0],
52                     },
53                     Vertex {
54                         position: [-1.0, 1.0],
55                         tex_coords: [0.0, 0.0],
56                     },
57                     Vertex {
58                         position: [1.0, 1.0],
59                         tex_coords: [1.0, 0.0],
60                     },
61                     Vertex {
62                         position: [1.0, -1.0],
63                         tex_coords: [1.0, 1.0],
64                     },
65                 ],
66             ).unwrap()
67         };
68
69         let index_buffer = glium::IndexBuffer::new(
70             display,
71             glium::index::PrimitiveType::TriangleStrip,
72             &[1 as u16, 2, 0, 3],
73         ).unwrap();
74
75         // compiling shaders and linking them together
76         let program = program!(display,
77         140 => {
78             vertex: "
79                 #version 140
80
81                 uniform mat4 model;
82                 uniform mat4 perspview;
83                 uniform int index;
84
85                 in vec2 position;
86                 in vec2 tex_coords;
87
88                 out vec2 v_tex_coords;
89                 out ivec4 v_fgcolor;
90
91                 void main() {
92                     gl_Position = perspview * model * vec4(position, 0.0, 1.0);
93
94                     // Characters are arranged in a 16x16 square.
95                     int xpos = index % 16;
96                     int ypos = index / 16;
97                     v_tex_coords = (tex_coords + vec2(xpos, ypos)) / 16.;
98                 }
99             ",
100
101             fragment: "
102                 #version 140
103                 uniform sampler2D tex;
104                 uniform vec4 bgcolor;
105                 uniform vec4 fgcolor;
106
107                 in vec2 v_tex_coords;
108                 out vec4 f_color;
109
110                 void main() {
111                     f_color = texture(tex, v_tex_coords).x == 0U ? bgcolor : fgcolor;
112                 }
113             "
114         }).unwrap();
115
116         let params = glium::DrawParameters {
117             depth: glium::Depth {
118                 test: glium::draw_parameters::DepthTest::IfLess,
119                 write: true,
120                 ..Default::default()
121             },
122             multisampling: true,
123             ..Default::default()
124         };
125
126         Text {
127             model: Matrix4::one(),
128             tex: tex,
129             vertex_buffer: vertex_buffer,
130             index_buffer: index_buffer,
131             program: program,
132             params: params,
133         }
134     }
135
136     pub fn draw(&self, frame: &mut glium::Frame, perspview: &[[f32; 4]; 4]) {
137         let uniforms =
138             uniform! {
139             model: array4x4(self.model),
140             perspview: *perspview,
141             tex: self.tex.sampled()
142                 .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
143             index: 'C' as i32,
144             // RGB values from http://unusedino.de/ec64/technical/misc/vic656x/colors/
145             bgcolor: [  53./255.,  40./255., 121./255.,   0.0/255. ] as [f32; 4],
146             fgcolor: [ 120./255., 106./255., 255./255., 188.0/255. ] as [f32; 4],
147         };
148         frame
149             .draw(
150                 &self.vertex_buffer,
151                 &self.index_buffer,
152                 &self.program,
153                 &uniforms,
154                 &self.params,
155             )
156             .unwrap();
157     }
158 }