1 module armos.graphics.material; 2 import armos.types; 3 import armos.math; 4 import armos.graphics; 5 6 /++ 7 材質を表すinterfaceです. 8 +/ 9 interface Material{ 10 public{ 11 /// 12 Material begin(); 13 14 /// 15 Material end(); 16 17 /// 18 Material uniform(in string name, in int i); 19 20 /// 21 Material uniform(in string name, in float f); 22 23 /// 24 Material uniform(in string name, in Color c); 25 26 /// 27 Material uniform(in string name, in Vector2f v); 28 29 /// 30 Material uniform(in string name, in Vector3f v); 31 32 /// 33 Material uniform(in string name, in Vector4f v); 34 35 /// 36 ref Vector4f uniform(in string name); 37 38 /// 39 Material texture(in string name, armos.graphics.Texture tex); 40 41 /// 42 armos.graphics.Texture texture(in string name); 43 44 /// 45 armos.graphics.Shader shader(); 46 47 /// 48 Material shader(armos.graphics.Shader s); 49 50 /// 51 Material loadImage(in string pathInDataDir, in string name); 52 }//public 53 54 }//interface Material 55 56 /// 57 mixin template MaterialImpl(){ 58 alias T = typeof(this); 59 import armos.math; 60 import armos.types:Color; 61 public{ 62 /// 63 T begin(){ 64 import armos.graphics:pushMaterialStack; 65 pushMaterialStack(this); 66 67 _shader.begin; 68 foreach (string key; _textures.keys) { 69 auto texture = _textures[key]; 70 if(texture){ 71 texture.begin; 72 } 73 } 74 import std.algorithm; 75 import std.array; 76 foreach (string key; _uniformsF.keys) { 77 _shader.uniform(key, _uniformsF[key]); 78 } 79 80 foreach (string key; _uniformsI.keys) { 81 _shader.uniform(key, _uniformsI[key]); 82 } 83 84 foreach (string key; _uniformsV2f.keys) { 85 _shader.uniform(key, _uniformsV2f[key]); 86 } 87 88 foreach (string key; _uniformsV3f.keys) { 89 _shader.uniform(key, _uniformsV3f[key]); 90 } 91 92 foreach (string key; _uniformsV4f.keys) { 93 _shader.uniform(key, _uniformsV4f[key]); 94 } 95 96 foreach (int index, string key; _textures.keys){ 97 _shader.uniformTexture(key, _textures[key], index); 98 } 99 return this; 100 } 101 102 /// 103 T end(){ 104 foreach (string key; _textures.keys) { 105 auto texture = _textures[key]; 106 if(texture){ 107 texture.end; 108 } 109 } 110 _shader.end; 111 112 import armos.graphics:popMaterialStack; 113 popMaterialStack; 114 return this; 115 } 116 117 /// 118 T uniform(in string Name, in int v){ 119 _uniformsI[Name] = v; 120 return this; 121 } 122 123 /// 124 T uniform(in string Name, in float v){ 125 _uniformsF[Name] = v; 126 return this; 127 } 128 129 /// 130 T uniform(in string Name, in Vector2f v){ 131 _uniformsV2f[Name] = v; 132 return this; 133 } 134 135 /// 136 T uniform(in string Name, in Vector3f v){ 137 _uniformsV3f[Name] = v; 138 return this; 139 } 140 141 /// 142 T uniform(in string Name, in Vector4f v){ 143 _uniformsV4f[Name] = v; 144 return this; 145 } 146 147 /// 148 T uniform(in string Name, in Color c){ 149 import std.conv; 150 _uniformsV4f[Name] = Vector4f(c.r.to!float/c.limit, c.g.to!float/c.limit, c.b.to!float/c.limit, c.a.to!float/c.limit); 151 return this; 152 } 153 154 /// 155 ref Vector4f uniform(in string name){ 156 return _uniformsV4f[name]; 157 } 158 159 /// 160 T texture(in string name, armos.graphics.Texture tex){ 161 _textures[name] = tex; 162 return this; 163 } 164 165 /// 166 armos.graphics.Texture texture(in string name){return _textures[name];} 167 168 /// 169 armos.graphics.Shader shader(){ 170 return _shader; 171 } 172 173 /// 174 T shader(armos.graphics.Shader s){ 175 _shader = s; 176 return this; 177 } 178 179 /// 180 T loadImage(in string pathInDataDir, in string name){ 181 auto image = new armos.graphics.Image(); 182 image.load(pathInDataDir); 183 texture(name, image.texture); 184 return this; 185 } 186 }//public 187 188 private{ 189 int[string] _uniformsI; 190 float[string] _uniformsF; 191 Vector2f[string] _uniformsV2f; 192 Vector3f[string] _uniformsV3f; 193 Vector4f[string] _uniformsV4f; 194 armos.graphics.Texture[string] _textures; 195 armos.graphics.Shader _shader; 196 }//private 197 198 } 199 200 /// 201 class DefaultMaterial : Material{ 202 mixin MaterialImpl; 203 204 /// 205 this(){ 206 _shader = new armos.graphics.Shader; 207 _shader.loadSources(defaultVertexShaderSource, "", defaultFragmentShaderSource); 208 } 209 }//class DefaultMaterial 210 211 /++ 212 +/ 213 class CustomShaderMaterial : Material{ 214 mixin MaterialImpl; 215 static CustomShaderMaterial loadFiles(in string shaderName){ 216 auto mat = new CustomShaderMaterial(); 217 mat.shader = new armos.graphics.Shader; 218 mat.shader.load(shaderName); 219 return mat; 220 } 221 222 static CustomShaderMaterial loadFiles(in string vertShaderPath, in string geomShaderPath, in string fragShaderPath){ 223 auto mat = new CustomShaderMaterial(); 224 mat.shader = new armos.graphics.Shader; 225 mat.shader.loadFiles(vertShaderPath, geomShaderPath, fragShaderPath); 226 return mat; 227 } 228 229 static CustomShaderMaterial loadString(in string vertShaderPath, in string geomShaderPath, in string fragShaderPath){ 230 auto mat = new CustomShaderMaterial(); 231 mat.shader = new armos.graphics.Shader; 232 mat.shader.loadSources(vertShaderPath, geomShaderPath, fragShaderPath); 233 return mat; 234 } 235 }//class CustomShaderMaterial 236 237 /// 238 class AutoReloadMaterial : Material{ 239 mixin MaterialImpl; 240 241 import fswatch; 242 243 /// 244 this(in string shaderPath){ 245 _shaderName = shaderPath; 246 247 import armos.utils.file; 248 _watcher = FileWatch(absolutePath("."), true); 249 250 _shader = new armos.graphics.Shader; 251 _shader.load(_shaderName); 252 } 253 254 /// 255 T begin(){ 256 loadShaderUpdateIfModified; 257 pushMaterialStack(this); 258 259 _shader.begin; 260 foreach (string key; _textures.keys) { 261 auto texture = _textures[key]; 262 if(texture){ 263 texture.begin; 264 } 265 } 266 import std.algorithm; 267 import std.array; 268 import armos.math; 269 foreach (string key; _uniformsF.keys) { 270 _shader.uniform(key, _uniformsF[key]); 271 } 272 273 foreach (string key; _uniformsI.keys) { 274 _shader.uniform(key, _uniformsI[key]); 275 } 276 277 foreach (string key; _uniformsV2f.keys) { 278 _shader.uniform(key, _uniformsV2f[key]); 279 } 280 281 foreach (string key; _uniformsV3f.keys) { 282 _shader.uniform(key, _uniformsV3f[key]); 283 } 284 285 foreach (string key; _uniformsV4f.keys) { 286 _shader.uniform(key, _uniformsV4f[key]); 287 } 288 289 foreach (int index, string key; _textures.keys){ 290 _shader.uniformTexture(key, _textures[key], index); 291 } 292 293 return this; 294 } 295 296 private{ 297 string _shaderName; 298 FileWatch _watcher; 299 300 void loadShaderUpdateIfModified(){ 301 foreach (event; _watcher.getEvents()){ 302 if(event.path == _shaderName ~ ".frag" || 303 event.path == _shaderName ~ ".geom" || 304 event.path == _shaderName ~ ".vert" 305 ){ 306 if(event.type == FileChangeEventType.modify){ 307 //TODO 308 auto shaderTmp = new armos.graphics.Shader; 309 import core.exception; 310 try{ 311 shaderTmp.load(_shaderName); 312 }catch(AssertError err){ 313 continue; 314 } 315 import std.stdio; 316 if(!shaderTmp.isLoaded)shaderTmp.log.writeln; 317 _shader = shaderTmp; 318 // _shader.load(_shaderName); 319 } 320 } 321 } 322 } 323 } 324 }//class DefaultMaterial 325 326 immutable string defaultVertexShaderSource = q{ 327 #version 330 328 329 uniform mat4 modelViewMatrix; 330 uniform mat4 projectionMatrix; 331 uniform mat4 modelViewProjectionMatrix; 332 uniform mat4 textureMatrix; 333 334 in vec4 vertex; 335 in vec3 normal; 336 in vec3 tangent; 337 in vec4 texCoord0; 338 in vec4 texCoord1; 339 in vec4 color; 340 341 out vec4 f_color; 342 out vec2 outtexCoord0; 343 out vec2 outtexCoord1; 344 345 void main(void) { 346 gl_Position = modelViewProjectionMatrix * vertex; 347 f_color = color; 348 outtexCoord0 = texCoord0.xy; 349 outtexCoord1 = texCoord1.xy; 350 } 351 }; 352 353 immutable string defaultFragmentShaderSource = q{ 354 #version 330 355 356 in vec4 f_color; 357 in vec2 outtexCoord0; 358 in vec2 outtexCoord1; 359 360 out vec4 fragColor; 361 362 uniform vec4 diffuse; 363 uniform sampler2D tex0; 364 uniform sampler2D tex1; 365 366 void main(void) { 367 fragColor = texture(tex0, outtexCoord0)*diffuse; 368 } 369 };