Created
January 11, 2015 13:33
-
-
Save hdon/7c2be9baa731c16e9751 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module com.codebad.shader; | |
import derelict.opengl3.gl3; | |
import file = std.file; | |
import std.exception : enforce; | |
import std.stdio : writeln, writefln; | |
import std.string : format, toStringz; | |
import std.traits : isPointer, PointerTarget; | |
import std.conv : to; | |
import std.path : baseName; | |
import std.traits : isSigned; | |
import std.algorithm : sort; | |
import ants.glutil; | |
private int[][string] availableShaders; | |
private bool isnum(char c) { return c >= '0' && c <= '9'; } | |
private int unstrVersion(string s) | |
{ | |
return s.length == 4 && s[1] == '.' && isnum(s[0]) && isnum(s[2]) && isnum(s[3]) ? | |
(s[0]-'0')*100 + (s[2]-'0')*10 + (s[3]-'0') : -1; | |
} | |
private void scan() | |
{ | |
size_t numShaders; | |
foreach (string d; file.dirEntries("glsl", file.SpanMode.shallow)) | |
{ | |
int v = unstrVersion(d[5..$]); | |
if (v >= 0) | |
foreach (string s; file.dirEntries(d, file.SpanMode.shallow)) | |
{ | |
if (s[$-5..$] == ".glsl") | |
{ | |
numShaders++; | |
availableShaders[s[d.length+1..$]] ~= v; | |
} | |
} | |
} | |
foreach (versions; availableShaders) | |
sort!"b < a"(versions); | |
writefln("scanned %d *.glsl files", numShaders); | |
} | |
private int glslVersion; | |
private string findBestShader(string shaderName) | |
{ | |
if (glslVersion == 0) | |
{ | |
const(char)*a = glGetString(GL_SHADING_LANGUAGE_VERSION); | |
glslVersion = unstrVersion(to!string(a[0..4])); | |
scan(); | |
} | |
if (shaderName !in availableShaders) | |
throw new Exception(format("could not find your shader named \"%s\"", shaderName)); | |
foreach (v; availableShaders[shaderName]) | |
if (v <= glslVersion) | |
return format("glsl/%01d.%02d/%s", v/100, v%100, shaderName); | |
throw new Exception(format("could not find shader \"%s\" in any compatible version", shaderName)); | |
} | |
GLuint loadShader(GLenum type, string filename) | |
{ | |
GLenum err; | |
GLuint shaderObject; | |
GLint iresult; | |
char[] source; | |
char* sourcePtr; | |
int souceLen; | |
// Create GL shader object | |
shaderObject = glCreateShader(type); | |
enforce(shaderObject != 0, "glCreateShader() failed"); | |
// Read shader source into memory | |
auto exactName = findBestShader(filename); | |
version (debugShaders) writefln("[shader] loading \"%s\"", exactName); | |
source = cast(char[])file.read(exactName); | |
// Send shader source to the GL | |
sourcePtr = source.ptr; | |
souceLen = cast(int)source.length; | |
glShaderSource(shaderObject, 1, &sourcePtr, &souceLen); | |
// Compile shaderObject | |
glCompileShader(shaderObject); | |
// Check compile result | |
glGetShaderiv(shaderObject, GL_COMPILE_STATUS, &iresult); | |
if (iresult == GL_FALSE) | |
{ | |
glGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, &iresult); | |
if (iresult <= 1) | |
{ | |
writefln("error: glCompileShader() failed with no error message"); | |
} | |
else | |
{ | |
char[] log = new char[iresult]; | |
glGetShaderInfoLog(shaderObject, iresult, null, log.ptr); | |
writeln("error: glCompileShader() failed:\n", log); | |
} | |
writeln("shader source:\n", source); | |
assert(0); | |
} | |
glErrorCheck(); | |
return shaderObject; | |
} | |
class Shader(GLenum type) | |
{ | |
GLuint shaderObject; | |
string filename; | |
this(string filename) | |
{ | |
this.filename = filename; | |
shaderObject = loadShader(type, filename); | |
//writeln("Shader() ", shaderObject); | |
} | |
~this() | |
{ | |
//writeln("glDeleteShader() ", shaderObject); | |
glDeleteShader(shaderObject); | |
} | |
override string toString() | |
{ | |
return format("[Shader Object filename=\"%s\" type=\"%s\"]", filename, type); | |
} | |
} | |
alias Shader!GL_VERTEX_SHADER VertexShader; | |
alias Shader!GL_FRAGMENT_SHADER FragmentShader; | |
alias Shader!GL_GEOMETRY_SHADER GeometryShader; | |
GLuint linkProgram(VertexShader vs, FragmentShader fs, GeometryShader gs=null) | |
{ | |
GLuint programObject; | |
GLint iresult; | |
// Create program object | |
programObject = glCreateProgram(); | |
enforce(programObject != 0, "error: glCreateProgram() failed"); | |
// Link | |
glAttachShader(programObject, vs.shaderObject); | |
glAttachShader(programObject, fs.shaderObject); | |
if (gs !is null) | |
glAttachShader(programObject, gs.shaderObject); | |
glLinkProgram(programObject); | |
// Handle link errors | |
glGetProgramiv(programObject, GL_LINK_STATUS, &iresult); | |
if (iresult == GL_FALSE) | |
{ | |
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &iresult); | |
if (iresult <= 1) | |
{ | |
writefln("error: glCompileShader() failed with no error message"); | |
} | |
else | |
{ | |
char[] log = new char[iresult]; | |
glGetProgramInfoLog(programObject, iresult, null, log.ptr); | |
writeln("error: glCompileShader() failed:\n", log); | |
} | |
writefln("Could not link program:\nvs: %s\nfs: %s\ngs: %s", vs, fs, gs); | |
assert(0); | |
} | |
return programObject; | |
} | |
class ShaderProgram | |
{ | |
GLuint programObject; | |
VertexShader vs; | |
FragmentShader fs; | |
this(VertexShader vs, FragmentShader fs) | |
{ | |
this.vs = vs; | |
this.fs = fs; | |
programObject = linkProgram(vs, fs); | |
glErrorCheck(); | |
} | |
this(string vsFilename, string fsFilename) | |
{ | |
this(new VertexShader(vsFilename), new FragmentShader(fsFilename)); | |
} | |
~this() | |
{ | |
glDeleteProgram(programObject); | |
} | |
GLint getUniformLocation(string name) | |
{ | |
return glGetUniformLocation(programObject, name.toStringz()); | |
} | |
GLint getAttribLocation(string name) | |
{ | |
return glGetAttribLocation(programObject, name.toStringz()); | |
} | |
GLuint getUniformLocationz(const char* name) | |
{ | |
return glGetUniformLocation(programObject, name); | |
} | |
GLint getAttribLocationz(const char* name) | |
{ | |
return glGetAttribLocation(programObject, name); | |
} | |
void use() | |
{ | |
glUseProgram(programObject); | |
glErrorCheck(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment