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 beginDefault; 65 return this; 66 } 67 68 /// 69 T end(){ 70 endDefault; 71 return this; 72 } 73 74 /// 75 T uniform(in string Name, in int v){ 76 _uniformsI[Name] = v; 77 return this; 78 } 79 80 /// 81 T uniform(in string Name, in float v){ 82 _uniformsF[Name] = v; 83 return this; 84 } 85 86 /// 87 T uniform(in string Name, in Vector2f v){ 88 _uniformsV2f[Name] = v; 89 return this; 90 } 91 92 /// 93 T uniform(in string Name, in Vector3f v){ 94 _uniformsV3f[Name] = v; 95 return this; 96 } 97 98 /// 99 T uniform(in string Name, in Vector4f v){ 100 _uniformsV4f[Name] = v; 101 return this; 102 } 103 104 /// 105 T uniform(in string Name, in Color c){ 106 import std.conv; 107 _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); 108 return this; 109 } 110 111 /// 112 ref Vector4f uniform(in string name){ 113 return _uniformsV4f[name]; 114 } 115 116 /// 117 T texture(in string name, armos.graphics.Texture tex){ 118 _textures[name] = tex; 119 return this; 120 } 121 122 /// 123 armos.graphics.Texture texture(in string name){return _textures[name];} 124 125 /// 126 armos.graphics.Shader shader(){ 127 return _shader; 128 } 129 130 /// 131 T shader(armos.graphics.Shader s){ 132 _shader = s; 133 return this; 134 } 135 136 /// 137 T loadImage(in string pathInDataDir, in string name){ 138 auto image = new armos.graphics.Image(); 139 image.load(pathInDataDir); 140 texture(name, image.texture); 141 return this; 142 } 143 }//public 144 145 private{ 146 int[string] _uniformsI; 147 float[string] _uniformsF; 148 Vector2f[string] _uniformsV2f; 149 Vector3f[string] _uniformsV3f; 150 Vector4f[string] _uniformsV4f; 151 armos.graphics.Texture[string] _textures; 152 armos.graphics.Shader _shader; 153 154 /// 155 T beginDefault(){ 156 import armos.graphics:pushMaterialStack; 157 pushMaterialStack(this); 158 _shader.begin; 159 _textures.begin; 160 sendUniformsToShader; 161 return this; 162 } 163 164 /// 165 T endDefault(){ 166 _textures.end; 167 _shader.end; 168 169 import armos.graphics:popMaterialStack; 170 popMaterialStack; 171 return this; 172 } 173 174 T sendUniformsToShader(){ 175 _uniformsF.sendTo(_shader); 176 _uniformsI.sendTo(_shader); 177 _uniformsV2f.sendTo(_shader); 178 _uniformsV3f.sendTo(_shader); 179 _uniformsV4f.sendTo(_shader); 180 _textures.sendTo(_shader); 181 return this; 182 } 183 }//private 184 185 } 186 187 void begin(armos.graphics.Texture[string] textures){ 188 foreach (string key; textures.keys) { 189 auto texture = textures[key]; 190 if(texture){ 191 texture.begin; 192 } 193 } 194 } 195 196 void end(armos.graphics.Texture[string] textures){ 197 foreach_reverse (string key; textures.keys) { 198 auto texture = textures[key]; 199 if(texture){ 200 texture.end; 201 } 202 } 203 } 204 205 void sendTo(U:E[K], E, K)(U uniform, armos.graphics.Shader shader){ 206 foreach (int i, string key; uniform.keys) { 207 static if(is(E == armos.graphics.Texture)){ 208 shader.uniformTexture(key, uniform[key], i); 209 }else{ 210 shader.uniform(key, uniform[key]); 211 } 212 } 213 } 214 215 /// 216 class DefaultMaterial : Material{ 217 mixin MaterialImpl; 218 219 /// 220 this(){ 221 _shader = new armos.graphics.Shader; 222 _shader.loadSources(defaultVertexShaderSource, "", defaultFragmentShaderSource); 223 } 224 }//class DefaultMaterial 225 226 /++ 227 +/ 228 class CustomShaderMaterial : Material{ 229 mixin MaterialImpl; 230 static CustomShaderMaterial loadFiles(in string shaderName){ 231 auto mat = new CustomShaderMaterial(); 232 mat.shader = new armos.graphics.Shader; 233 mat.shader.load(shaderName); 234 return mat; 235 } 236 237 static CustomShaderMaterial loadFiles(in string vertShaderPath, in string geomShaderPath, in string fragShaderPath){ 238 auto mat = new CustomShaderMaterial(); 239 mat.shader = new armos.graphics.Shader; 240 mat.shader.loadFiles(vertShaderPath, geomShaderPath, fragShaderPath); 241 return mat; 242 } 243 244 static CustomShaderMaterial loadString(in string vertShaderPath, in string geomShaderPath, in string fragShaderPath){ 245 auto mat = new CustomShaderMaterial(); 246 mat.shader = new armos.graphics.Shader; 247 mat.shader.loadSources(vertShaderPath, geomShaderPath, fragShaderPath); 248 return mat; 249 } 250 }//class CustomShaderMaterial 251 252 /// 253 class AutoReloadMaterial : Material{ 254 mixin MaterialImpl; 255 256 import fswatch; 257 258 /// 259 this(in string shaderPath){ 260 _shaderName = shaderPath; 261 262 import armos.utils.file; 263 _watcher = FileWatch(absolutePath("."), true); 264 265 _shader = new armos.graphics.Shader; 266 _shader.load(_shaderName); 267 } 268 269 /// 270 bool hasReloaded()const{ 271 return _hasReloaded; 272 } 273 274 /// 275 T checkAndUpdateShader(){ 276 _hasReloaded = false; 277 bool hasGotEvents; 278 FileChangeEvent[] events; 279 do{ 280 hasGotEvents = true; 281 import std.exception; 282 try{ 283 events = _watcher.getEvents(); 284 }catch(Exception e){ 285 hasGotEvents = false; 286 } 287 }while(!hasGotEvents); 288 289 foreach (event; events){ 290 if(event.type == FileChangeEventType.modify && (event.path == _shaderName ~ ".frag" || 291 event.path == _shaderName ~ ".geom" || 292 event.path == _shaderName ~ ".vert") 293 ){ 294 _shader.clearLog 295 .load(_shaderName); 296 _hasReloaded = _hasReloaded||true; 297 } 298 } 299 return this; 300 } 301 302 private{ 303 string _shaderName; 304 bool _hasReloaded = false; 305 FileWatch _watcher; 306 } 307 }//class DefaultMaterial 308 309 immutable string defaultVertexShaderSource = q{ 310 #version 330 311 312 uniform mat4 modelViewMatrix; 313 uniform mat4 projectionMatrix; 314 uniform mat4 modelViewProjectionMatrix; 315 uniform mat4 textureMatrix; 316 317 in vec4 vertex; 318 in vec3 normal; 319 in vec3 tangent; 320 in vec4 texCoord0; 321 in vec4 texCoord1; 322 in vec4 color; 323 324 out vec4 f_color; 325 out vec2 outtexCoord0; 326 out vec2 outtexCoord1; 327 328 void main(void) { 329 gl_Position = modelViewProjectionMatrix * vertex; 330 f_color = color; 331 outtexCoord0 = texCoord0.xy; 332 outtexCoord1 = texCoord1.xy; 333 } 334 }; 335 336 immutable string defaultFragmentShaderSource = q{ 337 #version 330 338 339 in vec4 f_color; 340 in vec2 outtexCoord0; 341 in vec2 outtexCoord1; 342 343 out vec4 fragColor; 344 345 uniform vec4 diffuse; 346 uniform sampler2D tex0; 347 uniform sampler2D tex1; 348 349 void main(void) { 350 fragColor = texture(tex0, outtexCoord0)*diffuse; 351 } 352 };