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 };