module ecs_utils.gfx.material; import bindbc.sdl; import bubel.ecs.std; import ecs_utils.gfx.shader; version(WebAssembly)import glad.gl.gles2; else version(Android)import glad.gl.gles2; else import glad.gl.gl; //import mutils.serializer.json; struct Material { void create() nothrow { data = Mallocator.make!Data; } bool load(const char[] path) nothrow { struct LoadData { @("malloc") string blend_mode; @("malloc") string vertex; @("malloc") string fragment; void dispose() nothrow { //if(blend_mode)Mallocator.instance.dispose(cast(char[])blend_mode); //if(vertex)Mallocator.instance.dispose(cast(char[])vertex); //if(fragment)Mallocator.instance.dispose(cast(char[])fragment); } } char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1]; cpath[0..$-1] = path[0..$]; cpath[$-1] = 0; SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r"); if(file) { size_t size = cast(size_t)SDL_RWsize(file); char[] buffer = Mallocator.makeArray!char(size); SDL_RWread(file,buffer.ptr,size,1); LoadData load_data; scope(exit)load_data.dispose(); /*JSONSerializer serializer = Mallocator.make!JSONSerializer; scope(exit)Mallocator.dispose(serializer); serializer.serialize!(Load.yes, true)(load_data,buffer);*/ //if(__ecs_used_backend == Backend.opengl) { Shader vsh; vsh.load(load_data.vertex); vsh.compile(); Shader fsh; fsh.load(load_data.fragment); fsh.compile(); Material.ShaderModule[1] modules = [Material.ShaderModule(vsh,fsh)]; attachModules(modules); } SDL_RWclose(file); load_data.dispose(); return true; } else return false; } void bind() nothrow { glUseProgram(data.modules[0].gl_handle); } enum BlendMode { opaque, additive, mixed } enum TransformMode { position, matrix } struct ShaderModule { Shader fragment_shader; Shader vertex_shader; uint gl_handle; } void attachModules(scope ShaderModule[] modules) nothrow { data.modules = Mallocator.makeArray(modules); } bool compile() nothrow { foreach(ref module_;data.modules) { module_.gl_handle = glCreateProgram(); glAttachShader(module_.gl_handle, module_.vertex_shader.data.gl_handle); glAttachShader(module_.gl_handle, module_.fragment_shader.data.gl_handle); } return true; } void bindAttribLocation(const char* name, uint location) nothrow { foreach(ref module_;data.modules) { glBindAttribLocation(module_.gl_handle, location, name); } } bool link() nothrow { foreach(ref module_;data.modules) { glLinkProgram(module_.gl_handle); GLint ok = 0; glGetProgramiv(module_.gl_handle, GL_LINK_STATUS, &ok); if(!ok) { SDL_Log("Program link error!"); return false; } } return true; } int getLocation(const char* name) { foreach(ref module_;data.modules) { int location = glGetUniformLocation(module_.gl_handle,name); if(location != -1)return location; } return -1; } void pushBindings() { foreach(i;0..data.bindings.length) { glUniform1i(data.bindings[i],cast(int)i); } } void pushUniforms(void* ptr) { foreach(ref Uniform uniform; data.uniforms) { void* local_ptr = ptr + uniform.offset; glUniform4fv(uniform.location,1,cast(float*)local_ptr); } } enum Type { float_, float4 } struct Uniform { Type type; int location; uint offset; } struct Data { BlendMode blend_mode = BlendMode.opaque; ShaderModule[] modules; TransformMode mode; Uniform[] uniforms; int[] bindings; } Data* data; }