1 module nanovg.glInterface; 2 3 // 4 // OpenGL Interfacing D 5 // Copyright (c) 2015 S.Percentage 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // Permission is granted to anyone to use this software for any purpose, 11 // including commercial applications, and to alter it and redistribute it 12 // freely, subject to the following restrictions: 13 // 1. The origin of this software must not be misrepresented; you must not 14 // claim that you wrote the original software. If you use this software 15 // in a product, an acknowledgment in the product documentation would be 16 // appreciated but is not required. 17 // 2. Altered source versions must be plainly marked as such, and must not be 18 // misrepresented as being the original software. 19 // 3. This notice may not be removed or altered from any source distribution. 20 // 21 22 import derelict.opengl3.gl3, derelict.opengl3.gl; 23 import std.typecons, std.string, std.algorithm; 24 import std.experimental.logger; 25 26 alias Size = Tuple!(int, "width", int, "height"); 27 bool raised(int flag)(int flagSet) { return (flagSet & flag) != 0; } 28 29 class GLShaderCompileError : Exception 30 { 31 public this(GLuint shader, string type) 32 { 33 GLint logLength; 34 GLchar[] log; 35 36 shader.glGetShaderiv(GLShaderInfo.LogLength, &logLength); 37 if(logLength > 0) 38 { 39 log.length = logLength; 40 shader.glGetShaderInfoLog(logLength, null, log.ptr); 41 super(type ~ " Compilation Error: " ~ log.ptr.fromStringz.idup); 42 } 43 else super(type ~ " Compilation Error: No info available."); 44 } 45 } 46 class GLProgramLinkError : Exception 47 { 48 public this(GLuint program) 49 { 50 GLint logLength; 51 GLchar[] log; 52 53 program.glGetProgramiv(GLProgramInfo.LogLength, &logLength); 54 if(logLength > 0) 55 { 56 log.length = logLength; 57 program.glGetProgramInfoLog(logLength, null, log.ptr); 58 super("Program Linking Error: " ~ log.ptr.fromStringz.idup); 59 } 60 else super("Program Linking Error: No info available."); 61 } 62 } 63 class GLException : Exception 64 { 65 public this(GLenum errcode) 66 { 67 super("OpenGL Error: 0x" ~ format("%04x", errcode)); 68 } 69 } 70 void glCheckError() 71 { 72 auto err = glGetError(); 73 if(err != GL_NO_ERROR) throw new GLException(err); 74 } 75 76 enum GLShaderInfo : GLenum 77 { 78 CompileStatus = GL_COMPILE_STATUS, 79 LogLength = GL_INFO_LOG_LENGTH, 80 } 81 enum GLProgramInfo : GLenum 82 { 83 LinkStatus = GL_LINK_STATUS, 84 LogLength = GL_INFO_LOG_LENGTH 85 } 86 87 static class GLPixelStore 88 { 89 static class Parameter(GLenum E) 90 { 91 static void opAssign(int i) 92 { 93 glPixelStorei(E, i); 94 } 95 } 96 97 alias Alignment = Parameter!GL_UNPACK_ALIGNMENT; 98 alias RowLength = Parameter!GL_UNPACK_ROW_LENGTH; 99 alias SkipPixels = Parameter!GL_UNPACK_SKIP_PIXELS; 100 alias SkipRows = Parameter!GL_UNPACK_SKIP_ROWS; 101 } 102 static class GLTexture2D 103 { 104 static class Parameter(GLenum E) 105 { 106 static void opAssign(int i) 107 { 108 glTexParameteri(GL_TEXTURE_2D, E, i); 109 } 110 } 111 112 static class Wrap 113 { 114 alias S = Parameter!GL_TEXTURE_WRAP_S; 115 alias T = Parameter!GL_TEXTURE_WRAP_T; 116 } 117 static class Filter 118 { 119 alias Min = Parameter!GL_TEXTURE_MIN_FILTER; 120 alias Mag = Parameter!GL_TEXTURE_MAG_FILTER; 121 } 122 } 123 static class ArrayData(GLenum T) 124 { 125 static void opAssign(E)(E[] ary) 126 { 127 glBufferData(T, ary.length * E.sizeof, ary.ptr, GL_STREAM_DRAW); 128 glCheckError(); 129 } 130 } 131 struct ByteRange 132 { 133 size_t offset, length; 134 } 135 static class GLUniformBuffer 136 { 137 alias ArrayData = .ArrayData!GL_UNIFORM_BUFFER; 138 static class BindRange 139 { 140 static void opIndexAssign(ByteRange br, GLint buffer_name, GLint ui) 141 { 142 info(false, "BindBufferRange: ", buffer_name, "(shader binded through ", ui, ") <=> ", br); 143 glBindBufferRange(GL_UNIFORM_BUFFER, ui, buffer_name, br.offset, br.length); 144 glCheckError(); 145 } 146 } 147 148 static int opDispatch(string op)() if(op == "OffsetAlignment") 149 { 150 int v; 151 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &v); 152 return v; 153 } 154 } 155 struct DisablePointer { /* empty */ } 156 alias PlainFloatPointer = Tuple!(int, "dim", size_t, "stride", size_t, "offset"); 157 static class GLArrayBuffer 158 { 159 alias ArrayData = .ArrayData!GL_ARRAY_BUFFER; 160 static class AttribPointer 161 { 162 static void opIndexAssign(PlainFloatPointer p, GLint l) 163 { 164 glEnableVertexAttribArray(l); glCheckError(); 165 glVertexAttribPointer(l, p.dim, GL_FLOAT, GL_FALSE, 166 cast(GLint)p.stride, cast(const(GLvoid)*)p.offset); 167 glCheckError(); 168 } 169 static void opIndexAssign(DisablePointer p, GLint l) 170 { 171 glDisableVertexAttribArray(l); 172 glCheckError(); 173 } 174 } 175 } 176 static class GLProgram 177 { 178 static class Uniform 179 { 180 static void opIndexAssign(GLint i, GLint l) out { glCheckError(); } body 181 { 182 glUniform1i(l, i); 183 } 184 static void opIndexAssign(float[2] v2, GLint l) out { glCheckError(); } body 185 { 186 glUniform2fv(l, 1, v2.ptr); 187 } 188 } 189 } 190 191 const GLuint NullTexture = 0; 192 const GLuint NullSampler = 0; 193 const GLuint DisableProgram = 0; 194 alias GLBlendFuncParams = Tuple!(GLenum, "src", GLenum, "dst"); 195 static class GLBlendPresets 196 { 197 // src + dst * (1.0f - src.alpha) 198 static const PremultipliedBlending = GLBlendFuncParams(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 199 } 200 alias GLStencilOpSet = Tuple!(GLenum, "stencilFail", GLenum, "depthFail", GLenum, "depthSucc"); 201 static class GLStencilOpPresets 202 { 203 static const Keep = GLStencilOpSet(GL_KEEP, GL_KEEP, GL_KEEP); 204 static const Zero = GLStencilOpSet(GL_ZERO, GL_ZERO, GL_ZERO); 205 static const IncrementOnSucceeded = GLStencilOpSet(GL_KEEP, GL_KEEP, GL_INCR); 206 } 207 alias GLStencilFuncParams = Tuple!(GLenum, "func", GLint, "refv", GLuint, "mask"); 208 // Switch Constant 209 enum : bool { Disable = false, Enable = true } 210 enum GLFaceDirection : GLenum 211 { 212 Front = GL_FRONT, Back = GL_BACK 213 } 214 enum GLPathDirection : GLenum 215 { 216 Clockwise = GL_CW, CounterClockwise = GL_CCW 217 } 218 static class GLSwitchOptions(GLenum E) 219 { 220 static void opAssign(bool sw) { (sw ? glEnable : glDisable)(E); } 221 } 222 static class GLTupleSetter(alias F, T) 223 { 224 static void opAssign(T p) { F(p.expand); } 225 } 226 static class GLSingleSetter(alias F, T) 227 { 228 static void opAssign(T p) { F(p); } 229 } 230 auto asGLbool(bool b) { return b ? GL_TRUE : GL_FALSE; } 231 static class GLContext 232 { 233 static class BindTexture(GLenum E) 234 { 235 static void opAssign(GLuint i) out { glCheckError(); } body 236 { 237 glBindTexture(E, i); 238 } 239 } 240 static class BindBuffer(GLenum E, T) 241 { 242 static void opAssign(T i) { info(false, "UniformBuffer?", E == GL_UNIFORM_BUFFER, " binding: ", i is null ? 0 : i.id); glBindBuffer(E, i is null ? 0 : i.id); } 243 } 244 static class VertexArray 245 { 246 static void opAssign(VertexArrayObject o) { glBindVertexArray(o is null ? 0 : o.id); } 247 } 248 static class RenderProgram 249 { 250 static void opAssign(GLuint p) { glUseProgram(p); } 251 } 252 static class Blend 253 { 254 alias Enable = GLSwitchOptions!GL_BLEND; 255 alias Func = GLTupleSetter!(glBlendFunc, GLBlendFuncParams); 256 } 257 static class CullFace 258 { 259 alias Enable = GLSwitchOptions!GL_CULL_FACE; 260 alias Direction = GLSingleSetter!(glCullFace, GLFaceDirection); 261 alias FrontFace = GLSingleSetter!(glFrontFace, GLPathDirection); 262 } 263 static class DepthTest 264 { 265 alias Enable = GLSwitchOptions!GL_DEPTH_TEST; 266 } 267 static class ScissorTest 268 { 269 alias Enable = GLSwitchOptions!GL_SCISSOR_TEST; 270 } 271 static class Stencil 272 { 273 alias EnableTest = GLSwitchOptions!GL_STENCIL_TEST; 274 alias Mask = GLSingleSetter!(glStencilMask, GLuint); 275 static class Operations 276 { 277 static void opAssign(GLStencilOpSet args) { glStencilOp(args.expand); } 278 static void opIndexAssign(GLStencilOpSet args, GLFaceDirection dir) 279 { 280 glStencilOpSeparate(dir, args.expand); 281 } 282 } 283 alias Func = GLTupleSetter!(glStencilFunc, GLStencilFuncParams); 284 } 285 static class ActiveTexture 286 { 287 static void opAssign(GLuint index) 288 { 289 glActiveTexture(GL_TEXTURE0 + index); 290 glCheckError(); 291 } 292 } 293 static class ColorMask 294 { 295 static void opAssign(bool[4] col) 296 { 297 glColorMask(col[0].asGLbool, col[1].asGLbool, col[2].asGLbool, col[3].asGLbool); 298 } 299 } 300 301 alias Texture2D = BindTexture!GL_TEXTURE_2D; 302 alias UniformBuffer = BindBuffer!(GL_UNIFORM_BUFFER, UniformBufferObject); 303 alias ArrayBuffer = BindBuffer!(GL_ARRAY_BUFFER, ArrayBufferObject); 304 } 305 306 // OpenGL Objects 307 class BufferObject 308 { 309 GLuint buffer; 310 311 @property id() { return this.buffer; } 312 313 public this() 314 { 315 glGenBuffers(1, &this.buffer); 316 } 317 ~this() 318 { 319 glDeleteBuffers(1, &this.buffer); 320 } 321 } 322 alias UniformBufferObject = BufferObject; 323 alias ArrayBufferObject = BufferObject; 324 class VertexArrayObject 325 { 326 GLuint buffer; 327 @property id() { return this.buffer; } 328 329 public this() 330 { 331 glGenVertexArrays(1, &this.buffer); 332 } 333 ~this() 334 { 335 glDeleteVertexArrays(1, &this.buffer); 336 } 337 }