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.mango;
35 import mango_engine.util;
36 import mango_engine.exception;
37 import mango_engine.graphics.backend;
38 
39 import std.exception : enforce;
40 
41 /++
42     Base class for a ShaderProgram. Implemented
43     by backends.
44     
45     This represents multiple shaders linked into a
46     program. Each shader is of a different type,
47     such as a Vertex Shader and Fragment Shader.
48 +/
49 abstract class ShaderProgram {
50     private shared Shader[ShaderType] shaders;
51     private SyncLock lock;
52 
53     this() @safe nothrow {
54         lock = new SyncLock();
55     }
56 
57     static ShaderProgram shaderProgramFactory(GraphicsBackendType backend) @safe {
58         import mango_engine.graphics.opengl.gl_shader : GLShaderProgram;
59 
60         mixin(GenFactory!("ShaderProgram"));
61     }
62 
63     void addShader(Shader shader) @trusted {
64         synchronized(lock) {
65             enforce(!(shader.type in shaders), new InvalidArgumentException("Attempted to add multiple shaders of same type."));
66     
67             shader.onShaderAdd();
68             addShader_(shader);
69             shaders[shader.type] = cast(shared) shader;
70         }
71     }
72 
73     void removeShader(in ShaderType shaderType) @trusted {
74         synchronized(lock) {
75             enforce(shaderType in shaders, new InvalidArgumentException("Attempted to remove Shader that was not added."));
76     
77             removeShader_((cast(Shader)shaders[shaderType]));
78             (cast(Shader) shaders[shaderType]).onShaderRemove();
79             shaders.remove(shaderType);
80         }
81     }
82     
83     /// This is called after all the shaders have been added.
84     abstract void prepareProgram() @system;
85     
86     abstract void addShader_(Shader shader) @system;
87     abstract void removeShader_(Shader shader) @system;
88 }
89 
90 /// Represents a type of Shader.
91 enum ShaderType {
92     /// A Vertex Shader that processes vertices.
93     SHADER_VERTEX,
94     /// A Fragment Shader that processes pixels.
95     SHADER_FRAGMENT,
96     /// A Compute Shader
97     SHADER_COMPUTE
98 }
99 
100 /++
101     The base shader class. All implementations
102     will extend this.
103 +/
104 abstract class Shader {
105     /// The shader's filename.
106     immutable string filename;
107     /// The shader's type
108     immutable ShaderType type;
109     
110     protected this(in string filename, in ShaderType type) @safe nothrow {
111         this.filename = filename;
112         this.type = type;
113     }
114     
115     static Shader shaderFactory(in string filename, in ShaderType type, GraphicsBackendType backend) @safe {
116         import mango_engine.graphics.opengl.gl_shader : GLShader;
117 
118         mixin(GenFactory!("Shader", "filename, type"));
119     }
120     
121     protected void onShaderRemove() @system {
122         cleanup();
123     }
124 
125     protected abstract void onShaderAdd() @system;
126     protected abstract void cleanup() @system;
127 }