1 module more.gl; 2 3 import std.stdio; 4 import std.conv; 5 import std..string; 6 7 //import glad.gl.enums; 8 import glad.gl.funcs; 9 import glad.gl.ext; 10 import glad.gl.loader; 11 import glad.gl.types; 12 13 import gl3n.linalg; 14 15 import more.common; 16 17 struct Vector2i 18 { 19 int x,y; 20 } 21 struct Vector2f 22 { 23 align(4): 24 float x,y; 25 26 this(float x, float y) 27 { 28 this.x = x; 29 this.y = y; 30 } 31 } 32 struct Vector3f 33 { 34 align(4): 35 float x,y,z; 36 this(float x, float y, float z) 37 { 38 this.x = x; 39 this.y = y; 40 this.z = z; 41 } 42 } 43 44 /// Reads the shader source code and appends a NULL character 45 /// to the end of it so it can be passed to glShaderSource 46 char[] readGLShader(string filename) 47 { 48 File file = File(filename); 49 scope(exit) file.close(); 50 51 ulong fileSizeULong = file.size(); 52 fileSizeULong++; // Add 1 for the ending NULL character 53 if(fileSizeULong > uint.max) throw new Exception(format( 54 "File '%s' is too large (%s bytes including the ending NULL)", filename, fileSizeULong)); 55 56 char[] contents = new char[cast(uint)fileSizeULong]; 57 file.readFullSize(contents[0..$-1]); 58 contents[$-1] = '\0'; 59 60 return contents; 61 } 62 63 64 unittest 65 { 66 startTest("readFileToCStrings"); 67 endTest("readFileToCStrings"); 68 } 69 70 uint loadShader(GLenum type, string filename) 71 { 72 return loadShader(type, filename, readGLShader(filename).ptr); 73 } 74 uint loadShader(GLenum type, string shaderName, const(char*) source) 75 { 76 char[512] error; 77 78 uint id = glCreateShader(type); 79 if(id == 0) throw new Exception("glCreateShader failed"); 80 scope(failure) glDeleteShader(id); 81 82 glShaderSource(id, 1, &source, null); 83 glCompileShader(id); 84 85 int errorLength; 86 glGetShaderInfoLog(id, error.length, &errorLength, error.ptr); 87 88 if(errorLength) { 89 char[] msg = "Failed to compile shader '" ~ shaderName ~ "': " ~ error[0..core.stdc..string.strlen(error.ptr)]; 90 throw new Exception(to!string(msg)); 91 } 92 return id; 93 } 94 95 96 struct ShaderVar 97 { 98 string name; 99 immutable(char)* zname; 100 101 GLint location; 102 103 this(string name) 104 { 105 this.name = name; 106 this.zname = name.toStringz(); 107 } 108 } 109 110 struct ShaderProgram 111 { 112 uint id; 113 114 void init() 115 { 116 this.id = glCreateProgram(); 117 if(this.id == 0) throw new Exception("glCreateProgram failed"); 118 } 119 void attachShader(GLenum type, string filename) 120 { 121 if(id == 0) init(); 122 attachShader(loadShader(type, filename)); 123 } 124 void attachShader(GLenum type, string shaderName, const(char*) source) 125 { 126 if(id == 0) init(); 127 attachShader(loadShader(type, shaderName, source)); 128 } 129 void attachShader(uint shaderID) 130 { 131 if(id == 0) init(); 132 glAttachShader(id, shaderID); 133 // TODO: check for errors 134 } 135 void link() 136 { 137 if(id == 0) throw new Exception("Cannot link until you attach shaders"); 138 139 glLinkProgram(id); 140 int linkResult; 141 glGetProgramiv(id, GL_LINK_STATUS, &linkResult); 142 if(linkResult == GL_FALSE) throw new Exception("Failed to link shader program"); 143 } 144 145 void use() 146 { 147 glUseProgram(id); 148 } 149 150 /+ 151 GLint getUniformLocation(string name) 152 { 153 GLint location = glGetUniformLocation(id, name); 154 if(location == -1) throw new Exception("Failed to get uniform '" ~ name ~ "' variable location"); 155 } 156 +/ 157 GLint getUniformLocation(const(char)* name) 158 { 159 GLint location = glGetUniformLocation(id, name); 160 if(location == -1) throw new Exception("Failed to get uniform '" ~ to!string(name) ~ "' variable location"); 161 return location; 162 } 163 /+ 164 GLint getAttributeLocation(string name) 165 { 166 GLint location = glGetAttribLocation(id, name); 167 if(location == -1) throw new Exception("Failed to get attribute '" ~ name ~ "' variable location"); 168 return location; 169 } 170 +/ 171 GLint getAttributeLocation(const(char)* name) 172 { 173 GLint location = glGetAttribLocation(id, name); 174 if(location == -1) throw new Exception("Failed to get attribute '" ~ to!string(name) ~ "' variable location"); 175 return location; 176 } 177 178 void getUniformLocations(ShaderVar[] vars...) 179 { 180 foreach(var; vars) { 181 var.location = glGetUniformLocation(id, var.zname); 182 if(var.location == -1) throw new Exception("Failed to get uniform '" ~ var.name ~ "' variable location"); 183 } 184 } 185 void getAttributeLocations(ShaderVar[] vars...) 186 { 187 foreach(var; vars) { 188 var.location = glGetAttribLocation(id, var.zname); 189 if(var.location == -1) throw new Exception("Failed to get attribute '" ~ var.name ~ "' variable location"); 190 } 191 } 192 } 193 194 195 void perspective(ref mat4 mat, float fieldOfViewYDegrees, float widthToHeightRatio, 196 float zClipNear, float zClipFar) 197 { 198 199 float yMax = zClipNear * tan(fieldOfViewYDegrees * PI / 360); 200 float xMax = yMax * widthToHeightRatio; 201 202 frustrum(mat, -xMax, xMax, -yMax, yMax, zClipNear, zClipFar); 203 } 204 void frustrum(ref mat4 mat, float left, float right, 205 float bottom, float top, float zNear, float zFar) 206 { 207 float temp = 2 * zNear; 208 float width = right - left; 209 float height = top - bottom; 210 float depth = zFar - zNear; 211 212 mat[0][0] = temp / width; 213 mat[0][1] = 0; 214 mat[0][2] = 0; 215 mat[0][3] = 0; 216 217 mat[1][0] = 0; 218 mat[1][1] = temp / height; 219 mat[1][2] = 0; 220 mat[1][3] = 0; 221 222 mat[2][0] = (right + left) / width; 223 mat[2][1] = (top + bottom) / height; 224 mat[2][2] = (-zFar - zNear) / depth; 225 mat[2][3] = -1; 226 227 mat[3][0] = 0; 228 mat[3][1] = 0; 229 mat[3][2] = (-temp * zFar) / depth; 230 mat[3][3] = 0; 231 }