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