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 version(mango_GLBackend) {
35     import mango_engine.game;
36     import mango_engine.graphics.shader;
37 
38     import blocksound.util : toCString;
39 
40     import derelict.opengl3.gl3;
41 
42     /// Gets the OpenGL constant for a specific ShaderType.
43     GLuint shaderTypeToGL(ShaderType type) @safe nothrow {
44         final switch(type) {
45             case ShaderType.SHADER_VERTEX:
46                 return GL_VERTEX_SHADER;
47             case ShaderType.SHADER_FRAGMENT:
48                 return GL_FRAGMENT_SHADER;
49             case ShaderType.SHADER_COMPUTE:
50                 return GL_COMPUTE_SHADER;
51         }
52     }
53 
54     class GLShaderProgram : ShaderProgram {
55         package GLuint programId;
56 
57         this(GameManager game) @safe {
58             super(game);
59 
60             game.renderer.submitOperation(&this.setup);
61         }
62 
63         private void setup() @trusted nothrow {
64             this.programId = glCreateProgram();
65         }
66 
67         void use() @system nothrow {
68             glUseProgram(this.programId);
69         }
70 
71         override {
72             void prepareForUse() @trusted {
73                 this.game.renderer.submitOperation(() {
74                     glLinkProgram(this.programId);
75 
76                     glValidateProgram(this.programId);
77                 });
78             }
79 
80             protected void onShaderAdd(Shader shader) @system 
81             in {
82                 assert((cast(GLShader) shader) !is null, "Shader instance must be of GLShader!");
83             } body {
84                 shared GLShader shader_ = cast(shared GLShader) shader;
85 
86                 this.game.renderer.submitOperation(() {
87                     debug(mango_GLShaderInfo) {
88                         import std.stdio;
89                         writeln("Attaching: ", shader_.shaderId);
90                     }
91                     glAttachShader(this.programId, shader_.shaderId);
92                 });
93             }
94 
95             protected void onShaderRemove(Shader shader) @system
96             in {
97                 assert((cast(GLShader) shader) !is null, "Shader instance must be of GLShader!");
98             } body {
99                 shared GLShader shader_ = cast(shared GLShader) shader;
100 
101                 this.game.renderer.submitOperation(() {
102                     glDetachShader(this.programId, shader_.shaderId);
103                 });
104             }
105         }
106     }
107 
108     class GLShader : Shader {
109         package immutable string source;
110         package shared GLuint shaderId;
111 
112         this(GameManager game, in string source, in ShaderType type) @safe {
113             super(game, source, type);
114             this.source = source;
115 
116             game.renderer.submitOperation(&this.setup);
117         }
118 
119         private void setup() @system {
120             this.shaderId = glCreateShader(shaderTypeToGL(type));
121             
122             char* source = toCString(this.source);
123             glShaderSource(this.shaderId, 1, &source, null);
124         }
125 
126         override {
127             protected void onShaderAdd() @system {
128                 this.game.renderer.submitOperation(() {
129                     debug(mango_GLShaderInfo) {
130                         import std.stdio;
131                         writeln("Compiling Shader! ", this.shaderId);
132                     }
133                     glCompileShader(this.shaderId);
134                 });
135             }
136 
137             protected void cleanup() @system {
138                 this.game.renderer.submitOperation(() {
139                     glDeleteShader(this.shaderId);
140                 });
141             }
142         }
143     }
144 }