1 module grape.material; 2 3 import derelict.opengl3.gl3; 4 import std.variant; 5 import std.stdio; 6 import grape.shader; 7 import grape.buffer; 8 9 alias AttributeType = Algebraic!(float[], int); 10 alias UniformType = Algebraic!(float[16], string, int, float[2], float[8], float); 11 12 class Material { 13 alias ParamType = Algebraic!(int[], bool, string, int, DrawMode, Texture, AttributeType[string][string], UniformType[string][string]); 14 public: 15 this(T...)(T params) { 16 init(); 17 set_param(params); 18 } 19 20 void set_param(T...)(T params) { 21 static if (params.length) { 22 static assert(params.length % 2 == 0, "The number of material's parameter must be an even number."); 23 auto key = params[0]; 24 static assert(is(typeof(key) : string), "The material parameter's key must be string."); 25 assert(key in _params, "Wrong material parameter's key named \"" ~ key ~ "\""); 26 auto value = params[1]; 27 28 _params[key] = value; 29 set_param(params[2..$]); 30 } 31 } 32 33 @property { 34 ShaderProgram program() { 35 return _program; 36 } 37 38 ParamType[string] params() { 39 return _params; 40 } 41 42 string name() { 43 return _name; 44 } 45 } 46 47 protected: 48 void init() { 49 _name = "none"; 50 _params["drawMode"] = DrawMode.Triangles; 51 } 52 53 void create_program(in string vertexShaderSource, in string fragmentShaderSource) { 54 Shader vs = new Shader(ShaderType.Vertex, vertexShaderSource); 55 Shader fs = new Shader(ShaderType.Fragment, fragmentShaderSource); 56 _program = new ShaderProgram(vs, fs); 57 } 58 59 ParamType[string] _params; 60 ShaderProgram _program; 61 string _name; 62 } 63 64 class ColorMaterial : Material { 65 public: 66 this(T...)(T params) { 67 super(params); 68 create_program(vertexShaderSource, fragmentShaderSource); 69 } 70 71 protected: 72 override void init() { 73 _name = "color"; 74 _params["drawMode"] = DrawMode.Triangles; 75 _params["color"] = [ 255, 255, 255 ]; 76 _params["wireframe"] = false; 77 } 78 79 private: 80 static immutable vertexShaderSource = q{ 81 attribute vec3 position; 82 attribute vec4 color; 83 uniform mat4 pvmMatrix; 84 varying vec4 vColor; 85 86 void main() { 87 vColor = color; 88 gl_Position = pvmMatrix * vec4(position, 1.0); 89 } 90 }; 91 92 static immutable fragmentShaderSource = q{ 93 varying vec4 vColor; 94 95 void main() { 96 gl_FragColor = vColor; 97 } 98 }; 99 } 100 101 class DiffuseMaterial : Material { 102 public: 103 this(T...)(T params) { 104 super(params); 105 create_program(vertexShaderSource, fragmentShaderSource); 106 } 107 108 protected: 109 override void init() { 110 _name = "diffuse"; 111 _params["drawMode"] = DrawMode.Triangles; 112 _params["color"] = [ 255, 255, 255 ]; 113 _params["wireframe"] = false; 114 } 115 116 private: 117 static immutable vertexShaderSource = q{ 118 attribute vec3 position; 119 attribute vec3 normal; 120 attribute vec4 color; 121 122 uniform vec3 lightPosition; 123 124 uniform mat4 pvmMatrix; 125 uniform mat4 invMatrix; 126 127 varying vec4 vColor; 128 129 void main() { 130 vec3 invLight = normalize(invMatrix * vec4(lightPosition, 0.0)).xyz; 131 float diffuse = clamp(dot(normal, invLight), 0.1, 1.0); 132 vColor = color * vec4(vec3(diffuse), 1.0); 133 gl_Position = pvmMatrix * vec4(position, 1.0); 134 } 135 }; 136 137 static immutable fragmentShaderSource = q{ 138 varying vec4 vColor; 139 140 void main() { 141 gl_FragColor = vColor; 142 } 143 }; 144 } 145 146 class ADSMaterial : Material { 147 public: 148 this(T...)(T params) { 149 super(params); 150 create_program(vertexShaderSource, fragmentShaderSource); 151 } 152 153 protected: 154 override void init() { 155 _name = "ads"; 156 _params["drawMode"] = DrawMode.Triangles; 157 _params["color"] = [ 255, 255, 255 ]; 158 _params["wireframe"] = false; 159 _params["ambientColor"] = [ 0, 0, 0 ]; 160 } 161 162 private: 163 static immutable vertexShaderSource = q{ 164 attribute vec3 position; 165 attribute vec3 normal; 166 attribute vec4 color; 167 168 uniform vec3 lightPosition; 169 uniform vec3 eyePosition; 170 uniform vec4 ambientColor; 171 172 uniform mat4 pvmMatrix; 173 uniform mat4 invMatrix; 174 175 varying vec4 vColor; 176 177 void main() { 178 vec3 invLight = normalize(invMatrix * vec4(lightPosition, 0.0)).xyz; 179 vec3 invEye = normalize(invMatrix * vec4(eyePosition, 0.0)).xyz; 180 vec3 halfLE = normalize(invLight + invEye); 181 float diffuse = clamp(dot(normal, invLight), 0.0, 1.0); 182 float specular = pow(clamp(dot(normal, halfLE), 0.0, 1.0), 50.0); 183 vec4 light = color * vec4(vec3(diffuse), 1.0) + vec4(vec3(specular), 1.0); 184 vColor = light + ambientColor; 185 gl_Position = pvmMatrix * vec4(position, 1.0); 186 } 187 }; 188 189 static immutable fragmentShaderSource = q{ 190 varying vec4 vColor; 191 192 void main() { 193 gl_FragColor = vColor; 194 } 195 }; 196 } 197 198 class TextureMaterial : Material { 199 public: 200 this(T...)(T params) { 201 super(params); 202 create_program(vertexShaderSource, fragmentShaderSource); 203 } 204 205 protected: 206 override void init() { 207 _name = "texture"; 208 _params["drawMode"] = DrawMode.Triangles; 209 } 210 211 private: 212 static immutable vertexShaderSource = q{ 213 attribute vec2 position; 214 attribute vec2 texCoord; 215 varying vec2 vTexCoord; 216 //uniform mat4 pvmMatrix; 217 218 void main() { 219 vTexCoord = texCoord; 220 gl_Position = vec4(position, 0.0, 1.0); 221 //gl_Position = pvmMatrix * vec4(position, 0.0, 1.0); 222 } 223 }; 224 225 static immutable fragmentShaderSource = q{ 226 uniform sampler2D tex; 227 varying vec2 vTexCoord; 228 229 void main() { 230 vec4 smpColor = texture(tex, vTexCoord); 231 gl_FragColor = smpColor; 232 } 233 }; 234 } 235 236 class ShaderMaterial : Material { 237 public: 238 this(T...)(T params) { 239 super(params); 240 create_program(*_params["vertexShader"].peek!(string), *_params["fragmentShader"].peek!(string)); 241 } 242 243 void set_uniform(T)(string key, T value) { 244 (*_params["uniforms"].peek!(UniformType[string][string]))[key]["value"] = value; 245 } 246 247 protected: 248 override void init() { 249 import grape.camera; 250 251 _name = "shader"; 252 _params["drawMode"] = DrawMode.Triangles; 253 _params["vertexShader"] = q{ 254 attribute vec3 position; 255 uniform mat4 pvmMatrix; 256 257 void main() { 258 gl_Position = pvmMatrix * vec4(position, 1.0); 259 } 260 }; 261 _params["fragmentShader"] = q{ 262 void main() { 263 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 264 } 265 }; 266 _params["uniforms"] = [ "pvmMatrix": [ "type": UniformType("mat4v"), "value": UniformType((new Camera).pvMat4.mat) ] ]; 267 _params["attributes"] = [ "position": [ "type": AttributeType(3), "value": AttributeType([ 0.0f, 0.0f, 0.0f ]) ] ]; 268 _params["map"] = new Texture; 269 } 270 } 271