1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Graphic.Shader;
25 
26 private:
27 
28 import derelict.opengl3.gl;
29 
30 import Dgame.Internal.m3;
31 import Dgame.Internal.Error;
32 
33 @nogc
34 char[] file_get_contents(string filename) nothrow {
35     import Dgame.Internal.d2c : toStringz;
36     import core.stdc.stdio;
37 
38     FILE* f = fopen(toStringz(filename), "rb");
39     if (f) {
40         scope(exit) fclose(f);
41 
42         fseek(f, 0, SEEK_END);
43         immutable size_t length = ftell(f);
44         fseek(f, 0, SEEK_SET);
45 
46         char[] buffer = make!(char[])(length * char.sizeof);
47         if (buffer.length)
48             fread(buffer.ptr, char.sizeof, length, f);
49 
50         return buffer;
51     }
52 
53     return null;
54 }
55 
56 public:
57 
58 /**
59  * The Shader struct manages a OpenGL Shader instance
60  * The Shader can be loaded and compiled. But to use it, you must pass the Shader to the Program (see below).
61  *
62  * Author: Randy Schuett (rswhite4@googlemail.com)
63  */
64 struct Shader {
65 private:
66     uint _shader;
67 
68 public:
69     /**
70      * The supported Shader-Types
71      */
72     enum Type {
73         Vertex = GL_VERTEX_SHADER, /// To use as a Vertex-Shader
74         Geometry = GL_GEOMETRY_SHADER, /// To use as a Geometry-Shader
75         Fragment = GL_FRAGMENT_SHADER, /// To use as a Fragment-Shader
76     }
77 
78     /**
79      * CTor
80      */
81     @nogc
82     this(Type type, string filename = null) nothrow {
83         glCreateShader(type);
84         if (filename)
85             this.loadFromFile(filename);
86     }
87 
88     /**
89      * Postblit is disabled
90      */
91     @disable
92     this(this);
93 
94     /**
95      * DTor
96      */
97     @nogc
98     ~this() nothrow {
99         glDeleteShader(_shader);
100     }
101 
102     /**
103      * Returns the internal Shader ID
104      */
105     @nogc
106     @property
107     uint id() const pure nothrow {
108         return _shader;
109     }
110 
111     /**
112      * Load the Shader-Source from a file.
113      *
114      * Note: The Shader will not be automatically compiled, use compile to do that by yourself
115      */
116     @nogc
117     void loadFromFile(string filename) const nothrow {
118         assert(_shader != 0, "Shader was not created so far");
119 
120         char[] buffer = file_get_contents(filename);
121         scope(exit) unmake(buffer);
122 
123         const char* ptr = buffer.ptr;
124         glShaderSource(_shader, 1, &ptr, null);
125     }
126 
127     /**
128      * Compiles the Shader
129      *
130      * Returns if the compilation was successful
131      */
132     @nogc
133     bool compile() const nothrow {
134         assert(_shader != 0, "Shader was not created so far");
135 
136         glCompileShader(_shader);
137 
138         int isCompiled = 0;
139         glGetShaderiv(_shader, GL_COMPILE_STATUS, &isCompiled);
140         if (isCompiled == GL_FALSE) {
141             int maxLength = 0;
142             glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &maxLength);
143             
144             //The maxLength includes the NULL character
145             char[] infoLog = make!(char[])(maxLength);
146             scope(exit) unmake(infoLog);
147 
148             glGetShaderInfoLog(_shader, maxLength, &maxLength, infoLog.ptr);
149             
150             print_fmt("Shader could not be compiled: %s\n", infoLog.ptr);
151 
152             return false;
153         }
154 
155         return true;
156     }
157 }