1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module g4d.shader.base; 8 import g4d.gl.buffer, 9 g4d.gl.lib, 10 g4d.gl.texture, 11 g4d.shader.matrix, 12 g4d.exception; 13 import gl3n.linalg; 14 import std.conv, 15 std.string; 16 17 /// A baseclass of shader. 18 abstract class Shader 19 { 20 protected static GLuint compileShader ( GLenum shaderType, string src ) 21 { 22 const csrc = src.toStringz; 23 24 GLuint shader = enforce!glCreateShader( shaderType ); 25 enforce!glShaderSource( shader, 1, &csrc, null ); 26 enforce!glCompileShader( shader ); 27 28 GLint status; 29 enforce!glGetShaderiv( shader, GL_COMPILE_STATUS, &status ); 30 if ( status == GL_FALSE ) { 31 ShaderException.throwShaderLog( shader ); 32 } 33 return shader; 34 } 35 36 /// Invalid shader program id. 37 enum NullId = 0; 38 39 protected GLuint _vertex; 40 protected GLuint _fragment; 41 protected GLuint _program; 42 protected GLuint _vao; 43 44 protected ShaderMatrix _matrix; 45 /// Data of translation, rotation and transformation. 46 @property ref matrix () { return _matrix; } 47 48 /// GLSL source code of vertex shader. 49 const pure @property string vertexSource (); 50 /// GLSL source code of fragment shader. 51 const pure @property string fragSource (); 52 53 /// 54 this () 55 { 56 _vertex = compileShader( GL_VERTEX_SHADER, vertexSource ); 57 scope(failure) enforce!glDeleteShader( _vertex ); 58 59 _fragment = compileShader( GL_FRAGMENT_SHADER, fragSource ); 60 scope(failure) enforce!glDeleteShader( _fragment ); 61 62 _program = enforce!glCreateProgram(); 63 scope(failure) enforce!glDeleteProgram( _program ); 64 enforce!glAttachShader( _program, _vertex ); 65 enforce!glAttachShader( _program, _fragment ); 66 enforce!glLinkProgram( _program ); 67 68 GLint status; 69 enforce!glGetProgramiv( _program, GL_LINK_STATUS, &status ); 70 if ( status == GL_FALSE ) { 71 ShaderException.throwProgramLog( _program ); 72 } 73 initVertexShader(); 74 initFragShader(); 75 76 enforce!glGenVertexArrays( 1, &_vao ); 77 use(); 78 } 79 80 /// 81 ~this () 82 { 83 dispose(); 84 } 85 /// Checks if the shader is disposed. 86 const @property disposed () 87 { 88 return _program == NullId; 89 } 90 /// Deletes all programs and shaders. 91 void dispose () 92 { 93 if ( !disposed ) { 94 enforce!glDeleteVertexArrays( 1, &_vao ); 95 enforce!glDeleteProgram( _program ); 96 enforce!glDeleteShader( _vertex ); 97 enforce!glDeleteShader( _fragment ); 98 } 99 _program = NullId; 100 } 101 102 protected GLint getUniformLoc ( string name ) 103 { 104 return enforce!glGetUniformLocation( _program, name.toStringz ); 105 } 106 protected GLint getAttribLoc ( string name ) 107 { 108 return enforce!glGetAttribLocation( _program, name.toStringz ); 109 } 110 111 protected void initVertexShader (); 112 protected void initFragShader (); 113 114 /// Checks the shader supports texture. 115 const @property bool textureSupport () { return false; } 116 117 /// Sets the shader binded. 118 const void use () 119 { 120 enforce!glUseProgram( _program ); 121 enforce!glBindVertexArray( _vao ); 122 } 123 124 /// Uploads matrix. 125 void uploadMatrix ( mat4 ); 126 127 /// Uploads position buffer. 128 void uploadPositionBuffer ( in ArrayBuffer ); 129 130 /// Uploads uv buffer. 131 void uploadUvBuffer ( in ArrayBuffer ) 132 { 133 throw new ShaderException( "This shader doesn't support texture." ); 134 } 135 /// Uploads texture. 136 void uploadTexture ( in Texture ) 137 { 138 throw new ShaderException( "This shader doesn't support texture." ); 139 } 140 141 /// Applies the matrix. 142 void applyMatrix () 143 { 144 uploadMatrix( _matrix.cache ); 145 } 146 147 /// Calls glDrawArrays with GL_TRIANGLE_FAN. 148 void drawFan ( size_t polyCnt ) 149 { 150 enforce!glDrawArrays( GL_TRIANGLE_FAN, 0, polyCnt.to!int ); 151 } 152 /// Calls glDrawArrays with GL_TRIANGLE_STRIP. 153 void drawStrip ( size_t polyCnt ) 154 { 155 enforce!glDrawArrays( GL_TRIANGLE_STRIP, 0, polyCnt.to!int ); 156 } 157 } 158 159 /// An exception type used in shader modules. 160 class ShaderException : G4dException 161 { 162 /// Checks if the shader throwed errors, and throws it. 163 static void throwShaderLog ( GLuint shader, string file = __FILE__, size_t line = __LINE__ ) 164 { 165 GLint logLength = 0; 166 enforce!glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logLength ); 167 168 auto log = new char[logLength]; 169 enforce!glGetShaderInfoLog( shader, logLength, &logLength, log.ptr ); 170 throw new ShaderException( "ShaderLog: "~log.to!string, file, line ); 171 } 172 173 /// Checks if the shader program throwed errors, and throws it. 174 static void throwProgramLog ( GLuint program, string file = __FILE__, size_t line = __LINE__ ) 175 { 176 GLint logLength = 0; 177 enforce!glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLength ); 178 179 auto log = new char[logLength]; 180 enforce!glGetProgramInfoLog( program, logLength, &logLength, log.ptr ); 181 throw new ShaderException( "ProgramLog: "~log.to!string, file, line ); 182 } 183 184 /// 185 this ( string msg, string file = __FILE__, size_t line = __LINE__ ) 186 { 187 super( msg, file, line ); 188 } 189 } 190 191 /// A struct that saves status of the shader, 192 /// and restores the shader using saved status. 193 struct ShaderStateSaver 194 { 195 protected Shader _target; 196 protected ShaderMatrix _backup; 197 198 /// 199 this ( Shader s ) { 200 _target = s; 201 _backup = s.matrix; 202 } 203 204 /// 205 ~this () 206 { 207 _target.matrix = _backup; 208 } 209 }