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
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use glin;
use graphics::{self, Vertex3DNormal};
use super::{Renderer3d, CreationContext, CreationProxy, Render3d, Renderer};
use glin::CreationContext as GlinCreationContext;
use std::borrow::Borrow;
use glin::RenderSurface;

/// A skybox from an environment map cubemap
pub struct Skybox<C = glin::CubeMap>{
    cubemap: C,
    geometry: glin::SimpleVao<Vertex3DNormal>,
    level: f32,
}

pub struct Builder{
    pub(crate) gl: CreationProxy
}

impl Builder{
    /// Create a skybox from a cubemap
    pub fn from_cubemap<C: Borrow<glin::CubeMap>>(&self, cubemap: C, radius: f32) -> Skybox<C> {
        let sphere = graphics::sphere(radius, 30, 30);
        let geometry = self.gl.to_simple_vao(&sphere).unwrap();
        Skybox{
            cubemap,
            geometry,
            level: 0.,
        }
    }

    /// Create a skybox from a cubemap level
    pub fn from_cubemap_level<C: Borrow<glin::CubeMap>>(&self, cubemap: C, radius: f32, level: f32) -> Skybox<C> {
        let sphere = graphics::sphere(radius, 30, 30);
        let geometry = self.gl.to_simple_vao(&sphere).unwrap();
        Skybox{
            cubemap,
            geometry,
            level,
        }
    }

    /// Create a skybox from a cubmap's faces loaded as images
    pub fn from_cubemap_faces<I: glin::Image>(&self, faces: &glin::cubemap::Faces<I>, radius: f32) -> Skybox {
        let cubemap = self.gl.new_cubemap().from_faces(faces).unwrap();
        let sphere = graphics::sphere(radius, 30, 30);
        let geometry = self.gl.to_simple_vao(&sphere).unwrap();
        Skybox{
            cubemap,
            geometry,
            level: 0.,
        }
    }

    /// Create a skybox from a dds or similar image containing a cubemap
    pub fn from_cubemap_image<I: glin::CubemapImage>(&self, image: &I, radius: f32) -> Skybox {
        let cubemap = self.gl.new_cubemap().from_cubemap_image(image).unwrap();
        let sphere = graphics::sphere(radius, 30, 30);
        let geometry = self.gl.to_simple_vao(&sphere).unwrap();
        Skybox{
            cubemap,
            geometry,
            level: 0.,
        }
    }

    /// Create a skybox from a level in a dds or similar image containing a cubemap
    pub fn from_cubemap_image_level<I: glin::CubemapImage>(&self, image: &I, radius: f32, level: f32) -> Skybox {
        let cubemap = self.gl.new_cubemap().from_cubemap_image(image).unwrap();
        let sphere = graphics::sphere(radius, 30, 30);
        let geometry = self.gl.to_simple_vao(&sphere).unwrap();
        Skybox{
            cubemap,
            geometry,
            level,
        }
    }
}

impl Skybox{
    /// Level to draw when the cubmap has several mip levels
    pub fn level(&self) -> f32{
        self.level
    }

    pub fn set_level(&mut self, level: f32){
        self.level = level;
    }
}

impl<C: Borrow<glin::CubeMap>> Render3d for Skybox<C>{
    fn render<R: RenderSurface>(&self, gl: &Renderer<R>){
        let program = shaders::get_program(gl);
        let uniforms = uniforms!{
            cubemap_tex: self.cubemap.borrow(),
            level: self.level,
        };

        let properties = &[
            glin::Property::CullFace(Some(glin::gl::FRONT)),
            glin::Property::DepthFunc(glin::gl::LEQUAL),
            #[cfg(feature="gl")]
            glin::Property::TextureCubemapSeamless(true),
        ];

        gl.with_properties(properties)
            .draw_vao(&self.geometry, program, &uniforms);

    }
}

mod shaders{
    use glin;
    program_cache!(glin::program::Settings{
        version: ::gl::default_glsl_version(),
        precission: glin::program::ShaderPrecision::High,
        defines: vec![],
        extensions: vec![],
        bindings: ::gl::default_attribute_bindings(),
        shaders: vec![
            (glin::gl::VERTEX_SHADER, include_str!("shaders/skybox.vs.glsl")),
            (glin::gl::FRAGMENT_SHADER, include_str!("shaders/skybox.fs.glsl")),
        ],
        .. Default::default()
    }, get_program, SHADER);
}