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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//!
//! A collection of effects implementing the [Effect] trait.
//!

macro_rules! impl_effect_body {
    ($inner:ident) => {
        fn fragment_shader_source(
            &self,
            lights: &[&dyn Light],
            color_texture: Option<ColorTexture>,
            depth_texture: Option<DepthTexture>,
        ) -> String {
            self.$inner()
                .fragment_shader_source(lights, color_texture, depth_texture)
        }

        fn id(
            &self,
            color_texture: Option<ColorTexture>,
            depth_texture: Option<DepthTexture>,
        ) -> u16 {
            self.$inner().id(color_texture, depth_texture)
        }

        fn fragment_attributes(&self) -> FragmentAttributes {
            self.$inner().fragment_attributes()
        }

        fn use_uniforms(
            &self,
            program: &Program,
            camera: &Camera,
            lights: &[&dyn Light],
            color_texture: Option<ColorTexture>,
            depth_texture: Option<DepthTexture>,
        ) {
            self.$inner()
                .use_uniforms(program, camera, lights, color_texture, depth_texture)
        }

        fn render_states(&self) -> RenderStates {
            self.$inner().render_states()
        }
    };
}

mod fog;
#[doc(inline)]
pub use fog::*;

mod copy;
#[doc(inline)]
pub use copy::*;

mod full_screen;
#[doc(inline)]
pub use full_screen::*;

mod fxaa;
#[doc(inline)]
pub use fxaa::*;

mod water;
#[doc(inline)]
pub use water::*;

pub(crate) mod lighting_pass;

use crate::renderer::*;
use std::ops::Deref;

///
/// Similar to [Material], the difference is that an effect needs the rendered color texture and/or depth texture of the scene to be applied.
/// Therefore an effect is always applied one at a time and after the scene has been rendered with the regular [Material].
///
pub trait Effect {
    ///
    /// Returns the fragment shader source for this effect.
    ///
    fn fragment_shader_source(
        &self,
        lights: &[&dyn Light],
        color_texture: Option<ColorTexture>,
        depth_texture: Option<DepthTexture>,
    ) -> String;

    ///
    /// Returns a unique ID for each variation of the shader source returned from [Effect::fragment_shader_source].
    ///
    /// **Note:** The first 16 bits are reserved to internally implemented effects, so if implementing the [Effect] trait
    /// outside of this crate, always return an id that is larger than or equal to `0b1u16 << 16`.
    ///
    fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16;

    ///
    /// Returns a [FragmentAttributes] struct that describes which fragment attributes,
    /// ie. the input from the vertex shader, are required for rendering with this effect.
    ///
    fn fragment_attributes(&self) -> FragmentAttributes;

    ///
    /// Sends the uniform data needed for this effect to the fragment shader.
    ///
    fn use_uniforms(
        &self,
        program: &Program,
        camera: &Camera,
        lights: &[&dyn Light],
        color_texture: Option<ColorTexture>,
        depth_texture: Option<DepthTexture>,
    );

    ///
    /// Returns the render states needed to render with this effect.
    ///
    fn render_states(&self) -> RenderStates;
}

impl<T: Effect + ?Sized> Effect for &T {
    impl_effect_body!(deref);
}

impl<T: Effect + ?Sized> Effect for &mut T {
    impl_effect_body!(deref);
}

impl<T: Effect> Effect for Box<T> {
    impl_effect_body!(as_ref);
}

impl<T: Effect> Effect for std::rc::Rc<T> {
    impl_effect_body!(as_ref);
}

impl<T: Effect> Effect for std::sync::Arc<T> {
    impl_effect_body!(as_ref);
}

impl<T: Effect> Effect for std::cell::RefCell<T> {
    impl_effect_body!(borrow);
}

impl<T: Effect> Effect for std::sync::RwLock<T> {
    fn fragment_shader_source(
        &self,
        lights: &[&dyn Light],
        color_texture: Option<ColorTexture>,
        depth_texture: Option<DepthTexture>,
    ) -> String {
        self.read()
            .unwrap()
            .fragment_shader_source(lights, color_texture, depth_texture)
    }

    fn id(&self, color_texture: Option<ColorTexture>, depth_texture: Option<DepthTexture>) -> u16 {
        self.read().unwrap().id(color_texture, depth_texture)
    }

    fn fragment_attributes(&self) -> FragmentAttributes {
        self.read().unwrap().fragment_attributes()
    }

    fn use_uniforms(
        &self,
        program: &Program,
        camera: &Camera,
        lights: &[&dyn Light],
        color_texture: Option<ColorTexture>,
        depth_texture: Option<DepthTexture>,
    ) {
        self.read()
            .unwrap()
            .use_uniforms(program, camera, lights, color_texture, depth_texture)
    }

    fn render_states(&self) -> RenderStates {
        self.read().unwrap().render_states()
    }
}