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
use crate::core::*;

///
/// A customizable cube effect.
/// Used for rendering into all 6 sides of a cube map texture.
///
pub struct ImageCubeEffect {
    program: Program,
    positions: VertexBuffer,
}

impl ImageCubeEffect {
    ///
    /// Creates a new cube effect which applies the effect defined in the given fragment shader source to a side of a cube map
    /// when calling on of the render functions.
    ///
    pub fn new(context: &Context, fragment_shader_source: &str) -> ThreeDResult<Self> {
        let program = Program::from_source(
            context,
            "uniform mat4 viewProjection;
            in vec3 position;
            out vec3 pos;
            
            void main()
            {
                pos = position;
                gl_Position = viewProjection * vec4(position, 1.0);
            }",
            fragment_shader_source,
        )?;

        let positions = VertexBuffer::new_with_static(context, &CPUMesh::cube().positions)?;
        Ok(Self { program, positions })
    }

    ///
    /// Applies the effect defined in the fragment shader source given at construction to the given side of a cube map.
    /// Must be called in a render target render function,
    /// for example in the callback function of [Screen::write].
    ///
    pub fn render(
        &self,
        side: CubeMapSide,
        render_states: RenderStates,
        viewport: Viewport,
    ) -> ThreeDResult<()> {
        let projection = perspective(degrees(90.0), viewport.aspect(), 0.1, 10.0);
        self.program
            .use_uniform_mat4("viewProjection", &(projection * side.view()))?;
        self.program
            .use_attribute_vec3("position", &self.positions)?;
        self.program.draw_arrays(render_states, viewport, 36);
        Ok(())
    }
}

impl std::ops::Deref for ImageCubeEffect {
    type Target = Program;

    fn deref(&self) -> &Self::Target {
        &self.program
    }
}