Render text with a C64 font!
authorBernie Innocenti <bernie@codewiz.org>
Sun, 18 Jun 2017 16:56:24 +0000 (12:56 -0400)
committerBernie Innocenti <bernie@codewiz.org>
Sun, 18 Jun 2017 16:56:24 +0000 (12:56 -0400)
c64-font.png [new file with mode: 0644]
lib.rs
main.rs
sound.rs
text.rs [new file with mode: 0644]

diff --git a/c64-font.png b/c64-font.png
new file mode 100644 (file)
index 0000000..61d5e56
Binary files /dev/null and b/c64-font.png differ
diff --git a/lib.rs b/lib.rs
index aaf2b3c708b4786b9183b8c0d690c305ec345e6b..c7026710cc0a85e03bb67c7ca6985943516a1b0a 100644 (file)
--- a/lib.rs
+++ b/lib.rs
@@ -2,6 +2,7 @@ extern crate cgmath;
 #[macro_use(uniform,program,implement_vertex)]
 extern crate glium;
 extern crate glutin;
+extern crate image;
 extern crate libxm;
 extern crate sdl2;
 
@@ -11,7 +12,17 @@ pub mod mandelwow;
 pub mod shaded_cube;
 pub mod sound;
 pub mod support;
+pub mod text;
 
 pub use bounding_box::BoundingBox;
 pub use cube::Cube;
 pub use shaded_cube::ShadedCube;
+
+pub fn screenshot(display : &glium::Display) {
+    let image: glium::texture::RawImage2d<u8> = display.read_front_buffer();
+    let image = image::ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
+    let image = image::DynamicImage::ImageRgba8(image).flipv();
+    let mut output = std::fs::File::create(&std::path::Path::new("screenshot.png")).unwrap();
+    image.save(&mut output, image::ImageFormat::PNG).unwrap();
+}
+
diff --git a/main.rs b/main.rs
index 769c16fba8774e3d6e4bb1b8fbbe36a1b9652206..aee2e868873135d1ac9e66812d54c0cac9e9fcde 100644 (file)
--- a/main.rs
+++ b/main.rs
@@ -4,7 +4,6 @@ extern crate cgmath;
 #[macro_use(uniform)]
 extern crate glium;
 extern crate glutin;
-extern crate image;
 
 use cgmath::{Euler, Matrix4, Rad, SquareMatrix, Vector3, Vector4, Zero};
 use cgmath::conv::array4x4;
@@ -19,14 +18,6 @@ use std::time::{Duration, Instant};
 #[cfg(target_os = "emscripten")]
 use std::os::raw::{c_int, c_void};
 
-fn screenshot(display : &glium::Display) {
-    let image: glium::texture::RawImage2d<u8> = display.read_front_buffer();
-    let image = image::ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
-    let image = image::DynamicImage::ImageRgba8(image).flipv();
-    let mut output = std::fs::File::create(&std::path::Path::new("screenshot.png")).unwrap();
-    image.save(&mut output, image::ImageFormat::PNG).unwrap();
-}
-
 fn gl_info(display : &glium::Display) {
     let version = *display.get_opengl_version();
     let api = match version {
@@ -84,6 +75,7 @@ fn main() {
 
     gl_info(&display);
 
+    let text = text::Text::new(&display);
     let mandelwow_program = mandelwow::program(&display);
     let bounding_box_program = bounding_box::solid_fill_program(&display);
     let shaded_program = shaded_cube::shaded_program(&display);
@@ -196,6 +188,8 @@ fn main() {
 
         mandelwow::draw(&display, &mut frame, &mandelwow_program, model, &camera, &bounds, wow);
 
+        text.draw(&mut frame, &perspview);
+
         frame.finish().unwrap();
         let time_after_draw = Instant::now();
 
index d7dae929fa75cf9df80097d8db954338662f5464..859decf8bd42cf3fff97b6a36a32dc31b6e9ce02 100644 (file)
--- a/sound.rs
+++ b/sound.rs
@@ -29,8 +29,8 @@ fn play_xm(raw_xm: &[u8]) -> SoundPlayer {
 
     let desired_spec = AudioSpecDesired {
         freq: Some(SAMPLE_RATE),
-        channels: Some(2u8),
-        samples: None,
+        channels: Some(2),
+        samples: Some(4096),  // 85ms
     };
     let device = sdl_audio.open_playback(None, &desired_spec, |actual_spec| {
         let xm = XMContext::new(&raw_xm, actual_spec.freq as u32).unwrap();
diff --git a/text.rs b/text.rs
new file mode 100644 (file)
index 0000000..c483846
--- /dev/null
+++ b/text.rs
@@ -0,0 +1,137 @@
+use cgmath::conv::array4x4;
+use cgmath::{Matrix4, One};
+use glium;
+use glium::{Surface, texture};
+use image;
+use std::io::Cursor;
+
+#[derive(Copy, Clone)]
+struct Vertex {
+    position: [f32; 2],
+    tex_coords: [f32; 2],
+}
+implement_vertex!(Vertex, position, tex_coords);
+
+pub struct Text<'a> {
+    tex: texture::CompressedSrgbTexture2d,
+    vertex_buffer: glium::VertexBuffer<Vertex>,
+    index_buffer: glium::IndexBuffer<u16>,
+    program: glium::Program,
+    params: glium::DrawParameters<'a>,
+    model: Matrix4<f32>,
+}
+
+impl<'a> Text<'a> {
+    pub fn new(display: &glium::Display) -> Text {
+        let image = image::load(Cursor::new(&include_bytes!("c64-font.png")[..]), image::PNG)
+            .unwrap()
+            .to_rgba();
+        let dimensions = image.dimensions();
+        let image =
+            glium::texture::RawImage2d::from_raw_rgba_reversed(image.into_raw(), dimensions);
+        let tex = glium::texture::CompressedSrgbTexture2d::new(display, image).unwrap();
+
+        // building the vertex buffer, which contains all the vertices that we will draw
+        let vertex_buffer = {
+            glium::VertexBuffer::new(
+                display,
+                &[
+                    Vertex {
+                        position: [-1.0, -1.0],
+                        tex_coords: [0.0, 0.0],
+                    },
+                    Vertex {
+                        position: [-1.0, 1.0],
+                        tex_coords: [0.0, 1.0],
+                    },
+                    Vertex {
+                        position: [1.0, 1.0],
+                        tex_coords: [1.0, 1.0],
+                    },
+                    Vertex {
+                        position: [1.0, -1.0],
+                        tex_coords: [1.0, 0.0],
+                    },
+                ],
+            ).unwrap()
+        };
+
+        let index_buffer = glium::IndexBuffer::new(
+            display,
+            glium::index::PrimitiveType::TriangleStrip,
+            &[1 as u16, 2, 0, 3],
+        ).unwrap();
+
+        // compiling shaders and linking them together
+        let program = program!(display,
+        140 => {
+            vertex: "
+                #version 140
+
+                uniform mat4 model;
+                uniform mat4 perspview;
+
+                in vec2 position;
+                in vec2 tex_coords;
+
+                out vec2 v_tex_coords;
+
+                void main() {
+                    gl_Position = perspview * model * vec4(position, 0.0, 1.0);
+                    // Characters are arranged in a 16x16 square.
+                    // Texture oordinates originate in the bottom-left corner.
+                    v_tex_coords = (tex_coords) / 16.0 + vec2(0. / 16., 15. / 16.);
+                }
+            ",
+
+            fragment: "
+                #version 140
+                uniform sampler2D tex;
+                in vec2 v_tex_coords;
+                out vec4 f_color;
+
+                void main() {
+                    f_color = texture(tex, v_tex_coords);
+                }
+            "
+        }).unwrap();
+
+        let params = glium::DrawParameters {
+            depth: glium::Depth {
+                test: glium::draw_parameters::DepthTest::IfLess,
+                write: true,
+                ..Default::default()
+            },
+            multisampling: true,
+            ..Default::default()
+        };
+
+        Text {
+            model: Matrix4::one(),
+            tex: tex,
+            vertex_buffer: vertex_buffer,
+            index_buffer: index_buffer,
+            program: program,
+            params: params,
+        }
+    }
+
+    pub fn draw(&self, frame: &mut glium::Frame, perspview: &[[f32; 4]; 4]) {
+        let uniforms = uniform! {
+            model: array4x4(self.model),
+            perspview: *perspview,
+            tex: self.tex.sampled()
+                //.minify_filter(glium::uniforms::MinifySamplerFilter::Nearest)
+                .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
+        };
+        frame
+            .draw(
+                &self.vertex_buffer,
+                &self.index_buffer,
+                &self.program,
+                &uniforms,
+                &self.params,
+            )
+            .unwrap();
+    }
+}