1 /*
2  * Copyright (c) 2007-2013 Scott Lembcke and Howling Moon Software
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 module demo.ChipmunkDemoShaderSupport;
23 
24 import core.stdc.stdlib;
25 
26 import std.conv;
27 import std.stdio;
28 import std..string;
29 
30 import demo.dchip;
31 
32 import glad.gl.all;
33 import glad.gl.loader;
34 
35 string SET_ATTRIBUTE(string program, string type, string name, string gltype)
36 {
37     return q{
38         SetAttribute(program, "%1$s", %2$s.%1$s.sizeof / GLfloat.sizeof, %3$s, %2$s.sizeof, cast(GLvoid *)%2$s.%1$s.offsetof);
39     }.format(name, type, gltype);
40 }
41 
42 /// Converts an OpenGL errorenum to a string
43 string toString(GLenum error)
44 {
45     switch (error)
46     {
47         case GL_INVALID_ENUM:
48             return "An unacceptable value is specified for an enumerated argument.";
49 
50         case GL_INVALID_VALUE:
51             return "A numeric argument is out of range.";
52 
53         case GL_INVALID_OPERATION:
54             return "The specified operation is not allowed in the current state.";
55 
56         case GL_INVALID_FRAMEBUFFER_OPERATION:
57             return "The framebuffer object is not complete.";
58 
59         case GL_OUT_OF_MEMORY:
60             return "There is not enough memory left to execute the command. WARNING: GL operation is undefined.";
61 
62         case GL_STACK_UNDERFLOW:
63             return "An attempt has been made to perform an operation that would cause an internal stack to underflow.";
64 
65         case GL_STACK_OVERFLOW:
66             return "An attempt has been made to perform an operation that would cause an internal stack to overflow.";
67 
68         default:
69             assert(0, format("Unhandled GLenum error state: '%s'", error));
70     }
71 }
72 
73 void CheckGLErrors()
74 {
75     for (GLenum err = glGetError(); err; err = glGetError())
76     {
77         if (err)
78         {
79             stderr.writefln("Error: - %s", err.toString());
80             stderr.writefln("GLError(%s:%d) 0x%04X\n", __FILE__, __LINE__, err);
81             assert(0);
82         }
83     }
84 }
85 
86 alias PFNGLGETSHADERIVPROC = fp_glGetShaderiv;
87 alias PFNGLGETSHADERINFOLOGPROC = fp_glGetProgramInfoLog;
88 
89 //typedef GLAPIENTRY void (*GETIV)(GLuint shader, GLenum pname, GLint *params);
90 //typedef GLAPIENTRY void (*GETINFOLOG)(GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *infoLog);
91 
92 static cpBool CheckError(GLint obj, GLenum status, PFNGLGETSHADERIVPROC getiv, PFNGLGETSHADERINFOLOGPROC getInfoLog)
93 {
94     GLint success;
95     getiv(obj, status, &success);
96 
97     if (!success)
98     {
99         GLint length;
100         getiv(obj, GL_INFO_LOG_LENGTH, &length);
101 
102         char* log = cast(char*)alloca(length);
103         getInfoLog(obj, length, null, log);
104 
105         stderr.writefln("Shader compile error for 0x%04X: %s\n", status, log.to!string);
106         return cpFalse;
107     }
108     else
109     {
110         return cpTrue;
111     }
112 }
113 
114 GLint CompileShader(GLenum type, string source)
115 {
116     GLint shader = glCreateShader(type);
117 
118     auto ssp = source.ptr;
119     int ssl = cast(int)(source.length);
120     glShaderSource(shader, 1, &ssp, &ssl);
121     glCompileShader(shader);
122 
123     // TODO return placeholder shader instead?
124     cpAssertHard(CheckError(shader, GL_COMPILE_STATUS, glGetShaderiv, glGetShaderInfoLog), "Error compiling shader");
125 
126     return shader;
127 }
128 
129 GLint LinkProgram(GLint vshader, GLint fshader)
130 {
131     GLint program = glCreateProgram();
132 
133     glAttachShader(program, vshader);
134     glAttachShader(program, fshader);
135     glLinkProgram(program);
136 
137     // todo return placeholder program instead?
138     cpAssertHard(CheckError(program, GL_LINK_STATUS, glGetProgramiv, glGetProgramInfoLog), "Error linking shader program");
139 
140     return program;
141 }
142 
143 cpBool ValidateProgram(GLint program)
144 {
145     // TODO
146     return cpTrue;
147 }
148 
149 void SetAttribute(GLuint program, string name, GLint size, GLenum gltype, GLsizei stride, GLvoid* offset)
150 {
151     GLint index = glGetAttribLocation(program, name.toStringz);
152     glEnableVertexAttribArray(index);
153     glVertexAttribPointer(index, size, gltype, GL_FALSE, stride, offset);
154 }