1 module ecs_utils.gfx.material;
2 
3 import bindbc.sdl;
4 
5 import bubel.ecs.std;
6 
7 import ecs_utils.gfx.shader;
8 
9 version(WebAssembly)import glad.gl.gles2;
10 else version(Android)import glad.gl.gles2;
11 else import glad.gl.gl;
12 
13 //import mutils.serializer.json;
14 
15 struct Material
16 {
17 
18     void create() nothrow
19     {
20         data = Mallocator.make!Data;
21     }
22 
23     bool load(const char[] path) nothrow
24     {
25         struct LoadData
26         {
27             @("malloc") string blend_mode;
28             @("malloc") string vertex;
29             @("malloc") string fragment;
30 
31             void dispose() nothrow
32             {
33                 //if(blend_mode)Mallocator.instance.dispose(cast(char[])blend_mode);
34                 //if(vertex)Mallocator.instance.dispose(cast(char[])vertex);
35                 //if(fragment)Mallocator.instance.dispose(cast(char[])fragment);
36             }
37         }
38 
39         char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1];
40         cpath[0..$-1] = path[0..$];
41         cpath[$-1] = 0;
42 
43         SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r");
44         if(file)
45         {
46             size_t size = cast(size_t)SDL_RWsize(file);
47             char[] buffer = Mallocator.makeArray!char(size);
48             SDL_RWread(file,buffer.ptr,size,1);
49 
50             LoadData load_data;
51             scope(exit)load_data.dispose();
52 
53             /*JSONSerializer serializer = Mallocator.make!JSONSerializer;
54             scope(exit)Mallocator.dispose(serializer);
55             serializer.serialize!(Load.yes, true)(load_data,buffer);*/
56 
57             //if(__ecs_used_backend == Backend.opengl)
58             {
59                 Shader vsh;
60                 vsh.load(load_data.vertex);
61                 vsh.compile();
62 
63                 Shader fsh;
64                 fsh.load(load_data.fragment);
65                 fsh.compile();
66 
67                 Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)];
68 
69                 attachModules(modules);
70             }
71 
72             SDL_RWclose(file);
73             load_data.dispose();
74             return true;
75         }
76         else return false;
77     }
78 
79     void bind() nothrow
80     {
81         final switch(data.blend_mode)
82         {
83             case BlendMode.mixed:
84                 glDepthMask(0);
85                 glEnable(GL_BLEND);
86                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
87                 break;
88             case BlendMode.opaque:
89                 glDepthMask(1);
90                 glDisable(GL_BLEND);
91                 break;
92             case BlendMode.additive:
93                 glDepthMask(0);
94                 glEnable(GL_BLEND);
95                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
96                 //glBlendFunc(GL_ONE, GL_ONE);
97                 break;
98         }
99 
100         glUseProgram(data.modules[0].gl_handle);
101     }
102     
103     enum BlendMode
104     {
105         opaque,
106         additive,
107         mixed
108     }
109 
110     enum TransformMode
111     {
112         position,
113         matrix
114     }
115     
116     struct ShaderModule
117     {
118         Shader fragment_shader;
119         Shader vertex_shader;
120         uint gl_handle;
121     }
122 
123     void attachModules(scope ShaderModule[] modules) nothrow
124     {
125         data.modules = Mallocator.makeArray(modules);
126     }
127 
128     bool compile() nothrow
129     {
130         foreach(ref module_;data.modules)
131         {
132             module_.gl_handle = glCreateProgram();
133             glAttachShader(module_.gl_handle, module_.vertex_shader.data.gl_handle);
134             glAttachShader(module_.gl_handle, module_.fragment_shader.data.gl_handle);
135         }
136 
137         return true;
138     }
139 
140     void bindAttribLocation(const char* name, uint location) nothrow
141     {
142         foreach(ref module_;data.modules)
143         {
144             glBindAttribLocation(module_.gl_handle, location, name);
145         }
146     }
147 
148     bool link() nothrow
149     {
150         foreach(ref module_;data.modules)
151         {
152             glLinkProgram(module_.gl_handle);
153 
154             GLint ok = 0;
155             glGetProgramiv(module_.gl_handle, GL_LINK_STATUS, &ok);
156             if(!ok)
157             {
158                 SDL_Log("Program link error!");
159                 return false;
160             }
161         }
162 
163         return true;
164     }
165 
166     int getLocation(const char* name)
167     {
168         foreach(ref module_;data.modules)
169         {
170             int location = glGetUniformLocation(module_.gl_handle,name);
171             if(location != -1)return location;
172         }
173         return -1;
174     }
175 
176     void pushBindings()
177     {
178         foreach(i;0..data.bindings.length)
179         {
180             glUniform1i(data.bindings[i],cast(int)i);
181         }
182     }
183 
184     void pushUniforms(void* ptr)
185     {
186         foreach(ref Uniform uniform; data.uniforms)
187         {
188             void* local_ptr = ptr + uniform.offset;
189             glUniform4fv(uniform.location,1,cast(float*)local_ptr);
190         }
191     }
192 
193     enum Type 
194     {
195         float_,
196         float4
197     }
198 
199     struct Uniform 
200     {
201         Type type;
202         int location;
203         uint offset;
204     }
205 
206     struct Data
207     {
208         BlendMode blend_mode = BlendMode.opaque;
209     
210         ShaderModule[] modules;
211 
212         TransformMode mode;
213 
214         Uniform[] uniforms;
215         int[] bindings;
216     }
217 
218     Data* data;
219 }