1 module unecht.core.components.material;
2 
3 import derelict.opengl3.gl3;
4 
5 import gl3n.linalg;
6 
7 import unecht.core.component;
8 import unecht.core.assets.texture;
9 
10 import unecht.gl.shader;
11 import unecht.gl.program;
12 import unecht.gl.texture;
13 
14 ///
15 struct GLMaterialUniforms
16 {
17     private GLProgram _program;
18 
19     void setColor(in vec4 _v)
20     {
21         _program.bind();
22         _program.setUniformVec4("globalColor", _v);
23     }
24 
25     void setMatWorld(const ref mat4 _v)
26     {
27         _program.bind();
28         _program.setUniformMatrix("matWorld", _v);
29     }
30 
31     void setViewDir(in vec3 _v)
32     {
33         _program.bind();
34         _program.setUniformVec3("v3ViewDir", _v);
35     }
36 }
37 
38 /// 
39 final class UEMaterial : UEComponent
40 {
41     mixin(UERegisterObject!());
42     
43     //TODO: remove shader hardwiring
44     static const string vs_shaded = cast(string)import("vs_shaded.glsl");
45     static const string fs_shaded = cast(string)import("fs_shaded.glsl");
46     
47     static const string vs_tex = cast(string)import("vs_tex.glsl");
48     static const string fs_tex = cast(string)import("fs_tex.glsl");
49     
50     static const string vs_flat = cast(string)import("vs_flat.glsl");
51     static const string fs_flat = cast(string)import("fs_flat.glsl");
52     
53     static const string vs_flatcolor = cast(string)import("vs_flatcolor.glsl");
54     static const string fs_flatcolor = cast(string)import("fs_flatcolor.glsl");
55 
56     ///
57     enum CullMode
58     {
59         cullNone,
60         cullFront,
61         cullBack
62     }
63 
64     ///
65     @Serialize bool polygonFill = true;
66     ///
67     @Serialize bool depthTest = true;
68     ///
69     @Serialize CullMode cullMode = CullMode.cullNone;
70     ///
71     @Serialize UETexture2D texture;
72 
73     ///
74     @property GLMaterialUniforms uniforms() { return GLMaterialUniforms(_program); }
75     ///
76     @property uint attribLocation(GLAtrribTypes _v) const { return _program.attribLocations[_v]; }
77     
78     ///
79     override void onCreate() {
80         super.onCreate;
81 
82         _program = new GLProgram();
83 
84         if(_vshader.length == 0 || _fshader.length == 0 || _shaderName.length == 0)
85             setProgram(vs_flat,fs_flat, "flat");
86         else
87             setProgram(_vshader, _fshader, _shaderName);
88     }
89 
90     ///
91     override void onDestroy() {
92         super.onDestroy;
93         
94         if(_program) _program.destroy();
95 
96         _program   = null;
97         texture    = null;
98     }
99 
100     ///
101     void setProgram(string _vs, string _fs, string _name)
102     {
103         import std.typecons:scoped;
104 
105         _fshader = _fs;
106         _vshader = _vs;
107         _shaderName = _name;
108 
109         auto vshader = scoped!GLShader();
110         auto fshader = scoped!GLShader();
111         scope(exit) vshader.destroy();
112         scope(exit) fshader.destroy();
113         
114         vshader.create(ShaderType.vertex, _vshader);
115         fshader.create(ShaderType.fragment, _fshader);
116         
117         _program.create(vshader,fshader, _name);
118     }
119     
120     ///
121     void preRender()
122     {
123         glPolygonMode( GL_FRONT_AND_BACK, polygonFill ? GL_FILL : GL_LINE );
124         
125         if(depthTest)
126         {
127             glEnable(GL_DEPTH_TEST);
128             glDepthFunc(GL_LEQUAL);
129             glDepthMask(GL_TRUE);
130         }
131         else
132             glDisable(GL_DEPTH_TEST);
133 
134         if(cullMode != CullMode.cullNone)
135         {
136             glEnable(GL_CULL_FACE);
137             glCullFace((cullMode == CullMode.cullFront) ? GL_FRONT : GL_BACK);
138         }
139         else
140         {
141             glDisable(GL_CULL_FACE);
142         }
143         
144         if(texture)
145         {
146             glActiveTexture(GL_TEXTURE0);
147             texture.bind();
148         }
149         
150         _program.bind();
151     }
152     
153     ///
154     void postRender()
155     {
156         _program.unbind();
157         
158         if(texture)
159         {
160             glActiveTexture(GL_TEXTURE0);
161             texture.unbind();
162         }
163 
164         if(cullMode != CullMode.cullNone)
165             glDisable(GL_CULL_FACE);
166         
167         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
168     }
169 
170     ///
171     void validate()
172     {
173         _program.validate();
174     }
175     
176 private:
177     GLProgram _program;
178 
179     @Serialize
180     string _vshader;
181     @Serialize
182     string _fshader;
183     @Serialize
184     string _shaderName;
185 }