1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use glium::backend::glutin_backend::GlutinFacade;
use glium::program;
use glium::Program;
use super::Config;
use std::fs::File;
use std::io::{self, Read};
use std::error::Error;

#[derive(Clone)]
pub struct GameContext {
    facade: GlutinFacade,
    config: Config, // TODO: we might want to wrap it into `Rc` (performance)
}

impl GameContext {
    pub fn new(facade: GlutinFacade, config: Config) -> Self {
        GameContext {
            facade: facade,
            config: config,
        }
    }

    pub fn get_facade(&self) -> &GlutinFacade {
        &self.facade
    }

    pub fn get_config(&self) -> &Config {
        &self.config
    }

    /// Loads vertex and fragment shader automatically to prevent recompiling
    /// the application
    /// everytime a shader is changed.
    pub fn load_program(&self, shader: &str) -> Result<Program, Box<Error>> {
        fn load_if_present(path: &str) -> Result<String, io::Error> {
            let mut f = try!(File::open(path));
            let mut buf = String::new();
            try!(f.read_to_string(&mut buf));
            Ok(buf)
        }

        let mut vert = try!(File::open(&format!("client/shader/{}.vert", shader)));
        let mut frag = try!(File::open(&format!("client/shader/{}.frag", shader)));

        let mut vert_buf = String::new();
        let mut frag_buf = String::new();
        try!(vert.read_to_string(&mut vert_buf));
        try!(frag.read_to_string(&mut frag_buf));

        let (tcs, tes);
        if self.config.tessellation {
            tcs = load_if_present(&format!("client/shader/{}.tcs", shader)).ok();
            tes = load_if_present(&format!("client/shader/{}.tes", shader)).ok();
        } else {
            // Don't even try to load the tessellation shaders if tessellation is off
            tcs = None;
            tes = None;
        }

        let source = program::SourceCode {
            vertex_shader: &vert_buf,
            tessellation_control_shader: tcs.as_ref().map(|s| s.as_str()),
            tessellation_evaluation_shader: tes.as_ref().map(|s| s.as_str()),
            geometry_shader: None,
            fragment_shader: &frag_buf,
        };

        let prog = Program::new(&self.facade, source);
        if let Err(ref e) = prog {
            warn!("failed to compile program '{}':\n{}", shader, e);
        }
        Ok(try!(prog))
    }

    // TODO: `load_post_processing_program` which loads a default vertex shader
}