1 /*
2  *  BSD 3-Clause License
3  *  
4  *  Copyright (c) 2016, Mango-Engine Team
5  *  All rights reserved.
6  *  
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions are met:
9  *  
10  *  * Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *  
13  *  * Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *  
17  *  * Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *  
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 module mango_engine.graphics.shader;
33 
34 import mango_engine.game;
35 import mango_engine.util;
36 
37 import mango_stl.misc;
38 
39 import std.exception;
40 
41 /// Represents a type of Shader.
42 enum ShaderType {
43     /// A Vertex Shader that processes vertices.
44     SHADER_VERTEX,
45     /// A Fragment Shader that processes pixels.
46     SHADER_FRAGMENT,
47     /// A Compute Shader
48     SHADER_COMPUTE
49 }
50 
51 /// Represents a ShaderProgram that is executed
52 abstract class ShaderProgram {
53     private shared GameManager _game;
54 
55     private shared Shader[ShaderType] shaders;
56     private shared Lock lock;
57 
58     /// The GameManager this ShaderProgram belongs to.
59     @property GameManager game() @trusted nothrow { return cast(GameManager) _game; }
60 
61     protected this(GameManager game) @trusted nothrow {
62         this._game = cast(shared) game;
63         this.lock = new Lock();
64     }
65 
66     static ShaderProgram build(GameManager game) @safe {
67         mixin(InterfaceClassFactory!("shader", "ShaderProgram", "game"));
68     }
69 
70     void addShader(Shader shader) @trusted {
71         synchronized(lock) {
72             enforce(!(shader.type in shaders), new Exception("Attempted to add multiple shaders of same type."));
73     
74             shader.onShaderAdd();
75             onShaderAdd(shader);
76             shaders[shader.type] = cast(shared) shader;
77         }
78     }
79 
80     void removeShader(in ShaderType shaderType) @trusted {
81         synchronized(lock) {
82             enforce(shaderType in shaders, new Exception("Attempted to remove Shader that was not added."));
83     
84             onShaderRemove((cast(Shader)shaders[shaderType]));
85             (cast(Shader) shaders[shaderType]).onShaderRemove();
86             shaders.remove(shaderType);
87         }
88     }
89 
90     void cleanup() @trusted {
91         foreach(type, shader; shaders) {
92             (cast(Shader) shader).cleanup();
93         }
94         shaders.clear();
95     }
96 
97     /++
98         Prepares the ShaderProgram for use. Make
99         sure to call after adding all the shaders
100         to be used.
101     +/
102     abstract void prepareForUse() @trusted;
103 
104     protected abstract void onShaderAdd(Shader shader) @system;
105     protected abstract void onShaderRemove(Shader shader) @system;
106 }
107 
108 /// Represents an individual Shader which can be added to a ShaderProgram.
109 abstract class Shader {
110     private shared GameManager _game;
111 
112     immutable ShaderType type;
113 
114     @property GameManager game() @trusted nothrow { return cast(GameManager) _game; }
115 
116     protected this(GameManager game, in string source, in ShaderType type) @trusted nothrow {
117         this._game = cast(shared) game;
118         this.type = type;
119     }
120 
121     static Shader build(GameManager game, in string source, in ShaderType type) @safe {
122         mixin(InterfaceClassFactory!("shader", "Shader", "game, source, type"));
123     }
124 
125     protected abstract void onShaderAdd() @system;
126 
127     protected void onShaderRemove() @system {
128         cleanup();
129     }
130 
131     protected abstract void cleanup() @system;
132 }