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.opengl.gl_shader;
33 
34 import mango_engine.util;
35 import mango_engine.exception;
36 import mango_engine.graphics.shader;
37 import mango_engine.graphics.opengl.gl_backend;
38 
39 import derelict.opengl3.gl3;
40 
41 /// Converts a ShaderType enum to a GLuint for OpenGL.
42 GLuint shaderTypeToGL(in ShaderType type) @safe nothrow {
43     final switch(type) {
44         case ShaderType.SHADER_VERTEX:
45             return GL_VERTEX_SHADER;
46         case ShaderType.SHADER_FRAGMENT:
47             return GL_FRAGMENT_SHADER;
48         case ShaderType.SHADER_COMPUTE:
49             return GL_COMPUTE_SHADER;
50     }
51 }
52 
53 class GLShaderProgram : ShaderProgram {
54     private GLuint programId;
55 
56     this() @safe {
57         gl_check();
58         
59         setup();
60     }
61     
62     private void setup() @trusted {
63         programId = glCreateProgram();
64     }
65 
66     /// Sets the shader for use.
67     void use() @system {
68         glUseProgram(programId);
69     }
70     
71     override {
72         void prepareProgram() @system {
73             glLinkProgram(programId);
74 
75             glValidateProgram(programId);
76         }
77         
78         void addShader_(Shader shader_) @system {
79             GLShader shader = cast(GLShader) shader_;
80             if(!shader) {
81                 throw new InvalidArgumentException("Shader must be instance of GLShader!");
82             }
83             glAttachShader(programId, shader.shaderId);
84         }
85         
86         void removeShader_(Shader shader_) @system {
87             GLShader shader = cast(GLShader) shader_;
88             if(!shader) {
89                 throw new InvalidArgumentException("Shader must be instance of GLShader!");
90             }
91             glDetachShader(programId, shader.shaderId);
92         }
93     }
94 }
95 
96 class GLShader : Shader {
97     package shared GLuint shaderId;
98 
99     /// Please use Shader.shaderFactory()
100     this(in string filename, in ShaderType type) @safe {
101         super(filename, type);
102 
103         gl_check();
104 
105         setup();
106     }
107 
108     private void setup() @trusted {
109         import blocksound.util : toCString;
110 
111         shaderId = glCreateShader(shaderTypeToGL(this.type));
112         char* source = toCString(readFileToString(filename));
113         glShaderSource(shaderId, 1, &source, null);
114     }
115 
116     override {
117         protected void onShaderAdd() @system nothrow {
118             glCompileShader(shaderId);
119         }
120 
121         protected void cleanup() @system nothrow {
122             glDeleteShader(shaderId);
123         }
124     }
125 }